2018黑龙江省赛(upc7215-upc7224)(solve8/10)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/passer__/article/details/82390444

题目没连接,除了Upc,没找到其他开发OJ有此题,如果有连接,请评论区留言下,谢谢~

A题:

题意:给你一个字符串问你只有一种字母的子串有多少。

思想:直接暴力连续的字符串数  结果等于每个连续字符的(长度*长度+1)/2

B 题:

不会~

C题

题意:给你x1,x2,y1,y2,(x1<x2,y1<y2)问你从x1到y1的同时x2到y2不想交的路径有多少

思想:Lindström–Gessel–Viennot定理  解决DAG图中n条不交叉路径问题,比赛的时候知道是这个但是脑子瓦特了,烦。

定理可以看下这个博客:https://blog.csdn.net/ftx456789/article/details/81132126

逆元预处理组合数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod =1e9+7;
const int maxn=1e6+5;
ll fac[maxn],inv[maxn];
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}
void init()
{
    fac[0]=1;
    for (int i=1;i<maxn;i++)
        fac[i]=fac[i-1]*i%mod;
    inv[maxn-1]=qpow(fac[maxn-1],mod-2);
    for (int i=maxn-2;i>=0;i--)
        inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(ll n,ll m){
    if (n<m) return 0;
    return ((fac[n]*inv[m]%mod)%mod*inv[n-m]%mod)%mod;
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll a,b,c,d;
        scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
        ll temp=(C(a+c,a)*C(b+d,b))%mod;
        ll Temp=(C(a+d,a)*C(b+c,b))%mod;
        temp=(temp-Temp+mod)%mod;
        printf("%lld\n",temp);
    }
    return 0;
}

D题

题意:给你n个数,然后m次询问,每次问你区间的数,是否是连续的数。

思想:莫队维护区间,RMQ求区间最值。莫队维护区间不同数的个数,RMQ求一下区间最大和最小值,看下当前区间出现的数是否等于Max-Min+1个即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int b[maxn];
int kuai[maxn];
int vis[maxn];
int Maxx[maxn][25];
int Minn[maxn][25]; 
int cnt[maxn];
struct node{
    int l;
    int r;
    int id;
}no[maxn];
int ans,n,m;
int cmp(node a,node b)
{
    if(kuai[a.l]==kuai[b.l])
        return a.r<b.r;
    return a.l<b.l;
}
void init()
{
    for(int j=1;j<=20;j++)
    {
        for(int i=1;i+(1<<j)<=n+1;i++)
        {
            Maxx[i][j]=max(Maxx[i][j-1],Maxx[i+(1<<(j-1))][j-1]);
            Minn[i][j]=min(Minn[i][j-1],Minn[i+(1<<(j-1))][j-1]);
        }
    }
}
int RMQmax(int l,int r)
{
    int k=0;
    while((1<<(k+1))<=r-l+1) 
        k++;
    return max(Maxx[l][k],Maxx[r-(1<<k)+1][k]);
}
int RMQmin(int l,int r)
{
    int k=0;
    while((1<<(k+1))<=r-l+1) 
        k++;
    return min(Minn[l][k],Minn[r-(1<<k)+1][k]);
}
void add(int l)
{
    cnt[a[l]]++;
    if(cnt[a[l]]==1)
        ans++;
}
void del(int l)
{
    cnt[a[l]]--;
    if(cnt[a[l]]==0)
        ans--;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(cnt,0,sizeof(cnt));
        scanf("%d%d",&n,&m);
        int black=sqrt(n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);  
            b[i]=a[i];
            kuai[i]=i/black+1;
            Maxx[i][0]=a[i];
            Minn[i][0]=a[i];
        }
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&no[i].l,&no[i].r);
            no[i].id=i;
        }
        sort(b+1,b+1+n);
        int k=unique(b+1,b+1+n)-b-1;
        for(int i=1;i<=n;i++)
            a[i]=lower_bound(b+1,b+1+k,a[i])-b;
        int l=1;
        int r=0;
        ans=0;
        sort(no+1,no+1+m,cmp);
        for(int i=1;i<=m;i++)
        {
            while(l<no[i].l)
                del(l++);
            while(l>no[i].l)
                add(--l);
            while(r<no[i].r) 
                add(++r);
            while(r>no[i].r)
                del(r--);
            int Max=RMQmax(no[i].l,no[i].r);
            int Min=RMQmin(no[i].l,no[i].r);
            if(Max-Min==ans-1)
                vis[no[i].id]=1;
            else
                vis[no[i].id]=0;
        }
        for(int i=1;i<=m;i++)
        {
            if(vis[i]==1)
                printf("YES\n");
            else
                printf("NO\n");
        }
    }
    return 0;
} 

E题

题意:给你x,y。问你x个东西均分y个人,让其中获得最多的人和最小的人的差值最小。

思路:x%y==0 则是0否则是1

F题

题意:给你2个串,问你A的子串和B的子串(长度相等)不同位置不超过k,这个子串的长度最长为多少。
思想:枚举A的子串的起点去匹配B串,枚举B串子串的起点去匹配A串。匹配的时候尺取法去匹配。n^2*T=8e7

#include<bits/stdc++.h>
using namespace std;
int k,ans;
char a[4005];
char b[4005];
void check(char c[],char d[])
{
	int sum=0;//标记已经有多少个不同 
	int len=min(strlen(c),strlen(d));
	
	for(int l=0,r=-1;l<len;l++)
	{
		while(r+1<len && sum+(c[r+1]!=d[r+1])<=k)
		{
			r++;
			sum+=c[r]!=d[r];
		}	
		ans=max(ans,r-l+1);
		sum-=(c[l]!=d[l]);	
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&k);
		scanf("%s%s",a,b);
		ans=0;	
		int Len=strlen(a);
		for(int i=0;i<Len;i++)	
			check(a+i,b);
		Len=strlen(b);
		for(int i=0;i<Len;i++) 
			check(b+i,a);
		printf("%d\n",ans);
	} 
	return 0;
} 

G题

题意:给你n个花的高度,每次修改n-1盆花,问你是否出现所有花一样高的局面,没有输出-1,有的话输出最少的时间。

思想:假设a[0]减去X下,a[1]减去Y下,a[2]减去Z下~~~~~这样先将全部拍个序列,考虑如果所有的花减去的长度等于sigma(max-a[i])(i>=1 && i<=n)的话,这样所有的花都到了一个统一的高度,考虑最矮的那个花是否可以sum-(Max-a[0])>0,如果不行的话那么就输出-1,如果行的话,那么输出就等于sum。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		for(int i=0;i<n;i++)
			scanf("%d",&a[i]);
		sort(a,a+n);
		int ans=0;
		for(int i=1;i<n;i++)
			ans+=a[n-1]-a[i];
		if(ans>=a[0])
			printf("-1\n");
		else
			printf("%d\n",ans+a[n-1]-a[0]);
	}
	return 0;
} 

H题

题意:就是给你n个立方体的边长和密度,然后给你一个底面积为S,高为H,现在有V体积水的一个容器,然后问你最后水的高度。

思想:我深切感觉题意有问题,题意没有说明重的一定都会没进去,可能出题人的没表达清楚?或者我菜?

密度>=1 全放进去,小于1的就按照比例放就好了,别忘了加上原来的水就行了。

I题

据说是AC自动机+DP

J题

题意:给你一个序列,问你最少交换多少次可以让序列变回一个有序的序列。

思想:如果是交换相邻的话,就变成了求逆序对,然而是随意交换的话,就相等于判断有多少个环即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int b[maxn];
int vis[maxn]; 
int Vis[maxn]; 
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		memset(vis,0,sizeof(vis));
		memset(Vis,0,sizeof(Vis));
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			b[i]=a[i];
		}
		sort(b,b+n);
		for(int i=0;i<n;i++)
			Vis[b[i]]=i;
		int ans=n;
		for(int i=0;i<n;i++) 
		{
			if(vis[i]==0)
			{
				int temp=i;
				while(vis[temp]==0) //跑一个环
				{
					vis[temp]=1;
					temp=Vis[a[temp]]; 
				} 
				ans--;//一个环少交换一次 
			}
		}
		printf("%d\n",ans);
	} 
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/passer__/article/details/82390444