zoukankan      html  css  js  c++  java
  • 11.21 考试

    T1
    给定一个字符串,有m次操作,可以使得相邻的字符交换,求最长相同的字符的长度最大的长度是多少;

    考虑确定一个位置的字符不动为答案,那么其他与他相同的字符向他的方向交换;

    设 f[i][j] 表示为 第i个字符不动,i字符后面的与i相同的字符转移j次,最多能使多少字符相邻;
    g[i][j] 表示之前的;

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=60;
    const int M=5010;
    int n,m,ans;
    char ch[N];
    int f[N][M],g[N][M];
    int main(){
    	freopen("string.in","r",stdin);
    	freopen("string.out","w",stdout);
    	scanf("%s",ch+1);
    	n=strlen(ch+1);
    	scanf("%d",&m);
    	for(int i=1;i<=n;i++){
    		char tt=ch[i];
    		int t=0,sum=0,num=0;
    		for(int j=i+1;j<=n;j++){
    			if(ch[j]!=tt) t++;
    			else{
    				num++;
    				sum+=t;
    				f[i][sum]=num;
    			}
    		}
    		t=0,sum=0,num=0;
    		for(int j=i-1;j>=1;j--){
    			if(ch[j]!=tt) t++;
    			else{
    				num++;
    				sum+=t;
    				g[i][sum]=num;
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			f[i][j]=max(f[i][j-1],f[i][j]);
    			g[i][j]=max(g[i][j-1],g[i][j]);
    		}
    	}
    //	for(int i=0;i<=m;i++) cout<<i<<" ";
    //	cout<<"
    ";
    //	for(int i=1;i<=n;i++){
    //		for(int j=0;j<=m;j++){
    //			cout<<f[i][j]<<" ";
    //		}
    //		cout<<"
    ";
    //		for(int j=0;j<=m;j++){
    //			cout<<g[i][j]<<" ";
    //		}
    //		cout<<"
    ";
    // 	}
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=m;j++){
    			ans=max(ans,f[i][j]+g[i][m-j]);
    //			if(f[i][j]+g[i][m-j]==3){
    //				cout<<i<<" "<<j<<"
    ";
    //			}
    		}
    	}
    	cout<<ans+1;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    /*
    ABCCDCDDC
    4
    
    ABCCDCDDC
    0
    
    AABCCBCADEADDEADBFA
    8
    
    AABAAABABABABBABA
    8
    */
    

    T2
    小林和亮亮在桃园里一起玩游戏。桃园里的桃树成行成列,刚好构成一个N×M的矩阵,亮亮在某
    些桃树下放置了一些小礼物,要求小林把所有树下的礼物全部收集起来。小林从左上角的桃
    树(1,1)出发,走到右下角的桃树(N,M)。他只能沿着路径向下或者向右走,某些桃树下有礼
    物,他必须到达所有有礼物的树下并把礼物收集起来。小林在出发前,想请你帮他计算一
    下,他有多少种不同的走法。由于答案可能很大,你只需要输出答案模100000000(10^8)后的值即可。

    考虑把地图分成k段,因为要收到所有礼物,所以收到的顺序是确定的,不同的方案数就是当前礼物到下一个礼物所产生的方案;
    可以证明(1,1,)到(n,m)只能向下或者向右走有多少种方案为C(n+m-2,m-1);
    但是这题就麻烦在模数不是质数,所以要用到扩展卢卡斯定理;

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define int long long
    using namespace std;
    const int N=1e4+7;
    struct node{
    	int x,y;
    }e[N];
    int n,m,k,ans=1,cnt;
    int cmp(node x,node y){
    	if(x.x==y.x) return x.y<y.y;
    	return x.x<y.x;
    }
    int a[10010],c[10010];
    int ksm(int a,int b,int p){
    	int res=1;
    	for(;b;b>>=1){
    		if(b&1) res=1LL*res*a%p;
    		a=1LL*a*a%p;
    	}
    	return res;
    }
    void exgcd(int a,int b,int &x,int &y){
    	if(b==0){
    		x=1;
    		y=0;
    		return;
    	}
    	exgcd(b,a%b,y,x);
    	y-=a/b*x;
    }
    int fac(int n,int p,int pk){
    	if(!n) return 1;
    	int res=1;
    	for(int i=1;i<pk;i++){
    		if(i%p) res=res*i%pk;
    	}
    	res=ksm(res,n/pk,pk);
    	for(int i=1;i<=n%pk;i++){
    		if(i%p) res=res*i%pk;
    	}
    	return res*fac(n/p,p,pk)%pk;
    }
    int inv(int a,int p){
    	int x=0,y=0;
    	exgcd(a,p,x,y);
    	return (x%p+p)%p;
    }
    int C(int n,int m,int p,int pk){
    	if(n<m) return 0;
    	int f1,f2,f3;
    	f1=fac(n,p,pk),f2=fac(m,p,pk),f3=fac(n-m,p,pk);
    	int num=0;
    	for(int i=n;i;i/=p) num+=i/p;
    	for(int i=m;i;i/=p) num-=i/p;
    	for(int i=n-m;i;i/=p) num-=i/p;
    	return f1*inv(f2,pk)%pk*inv(f3,pk)%pk*ksm(p,num,pk)%pk;
    }
    int CRT(int cnt){
    	int M=1,res=0;
    	for(int i=1;i<=cnt;i++) M*=c[i];
    	for(int i=1;i<=cnt;i++){
    		int tt=M/c[i];
    		res=(res+a[i]*tt%M*inv(tt,c[i])%M)%M;
    	}
    	return (res+M)%M;
    }
    int exlucas(int n,int m,int p){
    	for(int i=2;i*i<=p;i++){
    		int tt=1;
    		while(p%i==0){
    			tt*=i;
    			p/=i;
    		}
    		if(tt>1){
    			a[++cnt]=C(n,m,i,tt);
    			c[cnt]=tt;
    		}
    	}
    	if(p>1){
    		a[++cnt]=C(n,m,p,p);
    		c[cnt]=p;
    	}
    	return CRT(cnt);
    }
    main(){
    	freopen("peach.in","r",stdin);
    	freopen("peach.out","w",stdout);
    	scanf("%lld%lld%lld",&n,&m,&k);
    	for(int i=1;i<=k;i++){
    		scanf("%lld%lld",&e[i].x,&e[i].y);
    	}
    	sort(e+1,e+k+1,cmp);
    	e[0].x=1;
    	e[0].y=1;
    	e[++k].x=n;
    	e[k].y=m;
    //	cout<<exlucas(5,2,100000000)<<"
    ";
    	for(int i=1;i<=k;i++){
    		int tx=e[i].x-e[i-1].x+1;
    		int ty=e[i].y-e[i-1].y+1;
    		if(tx<=0||ty<=0){
    			cout<<0;
    			return 0;
    		}
    		cnt=0;
    //		cout<<tx<<" "<<ty<<"
    ";
    //		cout<<exlucas(tx+ty-2,tx-1,100000000)<<"
    ";
    		ans=1LL*ans*exlucas(tx+ty-2,tx-1,100000000)%100000000;
    	}
    	cout<<ans;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    /*
    5 4 1
    2 2
    
    5 4 2
    2 2
    2 3
    */
    
  • 相关阅读:
    团队开发冲刺第十五天
    团队开发冲刺第十四天
    团队开发冲刺第十三天
    团队开发冲刺第十二天
    团队开发冲刺第十一天
    团队开发冲刺第十天
    幸运抽奖案例
    java中如何数组是如何赋值的?
    使用java中的String类操作复杂的字符串
    java中随机生成26个字母组合的随机验证码
  • 原文地址:https://www.cnblogs.com/Aswert/p/14034796.html
Copyright © 2011-2022 走看看