• 【Codeforces #131 Div2】Solutions


    【A System of Equations】

      http://www.codeforces.com/contest/214/problem/A

      题目大意:给定n,m,问有多少二元组(a,b)满足  ,其中a,b>0。

      由于n很小,直接枚举a,b的值即可,复杂度O(n²)。

    #include <iostream>
    using namespace std;
    int n,m;
    long long ans=0;
    int main(){
    	cin>>n>>m;
    	for(int i=0;i<=1000;i++)
    		for(int j=0;j<=1000;j++)
    			if(i*i+j==n && i+j*j==m) ans++;
    	cout<<ans<<endl;
    	return 0;
    }
    

    【B Hometask】

      http://www.codeforces.com/contest/214/problem/B

      题目大意:给出n个数字,要求用这n个数字中的一些拼成一个新数字,使新数字能被2,3,5整除,且新数字尽量大。

      能同时被2,5整除的话,结尾必须是0,这样可以排除一种无解情况。

      能被3整除的话,个位数字加起来必须是3的整数倍。

      如果给出数字有0的话,我们就先放一个0到新数字的个位上,问题转化成,去掉尽量少的数(即选取尽量多的数),使得和能被3整除。

      先假设所有数字都选取,和为sum,sum模3有三种情况:

        1)sum mod 3=0   将数字从大到小排序即可。

        2)sum mod 3=1    ①从数列中去除一个数x,使得x mod 3=1;

                     ②若①无法实现则去除两个数i,j,使得(i+j) mod 3=1;

        3)sum mod 3=2    ①从数列中去除一个数x,使得x mod 3=2;

                     ②若①无法实现则去除两个数i,j,使得(i+j) mod 3=2;

      剩下的数列就符合条件了。

      为什么最多删掉两个数就能符合要求,那么删掉更多的数呢?

      可以证明:若存在i,j,k,(i+j+k)mod 3=m (m=0,1,2), 一定存在x(i,j,k),且x≡(i+j+k)(mod 3),所以这种情况下只需要删除一个数。

      代码很难看,重在思路……

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    int a[100010],n;
    long long sum=0;
    bool flag=false;
    int vis[100];
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		vis[a[i]]++;
    		sum+=a[i];
    		if(!a[i]) flag=true;
    	}
    	if(!sum){
    		cout<<"0"<<endl;
    		return 0;
    	}
    	if(!flag){
    		cout<<"-1"<<endl;
    		return 0;
    	}
    	sort(a+1,a+1+n,greater<int>());
    	int delta=sum%3;
    	if(!delta){
    		for(int i=1;i<=n;i++) printf("%d",a[i]);
    		cout<<endl;
    		return 0;
    	}else if(delta==1){
    		for(int i=1;i<=9;i++)
    			if(vis[i] && i%3==1){
    				for(int j=1;j<=n;j++)
    					if(a[j]==i){a[j]=0;break;}
    				sum-=i;
    				if(!sum){
    					cout<<"0"<<endl;
    					return 0;
    				}
    				sort(a+1,a+1+n,greater<int>());
    				for(int i=1;i<n;i++) printf("%d",a[i]);
    				cout<<endl;
    				return 0;
    			}
    		for(int i=1;i<=9;i++)
    			for(int j=1;j<=9;j++)
    				if((i+j)%3==1){
    					if(i==j && vis[i]>1){
    						for(int k=1;k<=n;k++)
    							if(a[k]==i){a[k]=0,a[k+1]=0;break;}
    						sum=sum-2*i;
    						if(!sum){
    							cout<<"0"<<endl;
    							return 0;
    						}
    						sort(a+1,a+1+n,greater<int>());
    						for(int i=1;i<n-1;i++) printf("%d",a[i]);
    						cout<<endl;
    						return 0;
    					}else if(i!=j && vis[i] && vis[j]){
    						for(int k=1;k<=n;k++)
    							if(a[k]==i){a[k]=0;break;}
    						for(int k=1;k<=n;k++)
    							if(a[k]==j){a[k]=0;break;}
    						sum-=i,sum-=j;
    						if(!sum){
    							cout<<"0"<<endl;
    							return 0;
    						}
    						sort(a+1,a+1+n,greater<int>());
    						for(int i=1;i<n-1;i++) printf("%d",a[i]);
    						cout<<endl;
    						return 0;
    					}
    				}
    	}else if(delta==2){
    		for(int i=1;i<=9;i++)
    			if(vis[i] && i%3==2){
    				for(int j=1;j<=n;j++)
    					if(a[j]==i){a[j]=0;break;}
    				sum-=i;
    				if(!sum){
    					cout<<"0"<<endl;
    					return 0;
    				}
    				sort(a+1,a+1+n,greater<int>());
    				for(int i=1;i<n;i++) printf("%d",a[i]);
    				cout<<endl;
    				return 0;
    			}
    		for(int i=1;i<=9;i++)
    			for(int j=1;j<=9;j++)
    				if((i+j)%3==2){
    					if(i==j && vis[i]>1){
    						for(int k=1;k<=n;k++)
    							if(a[k]==i){a[k]=0,a[k+1]=0;break;}
    							sum=sum-2*i;
    						if(!sum){
    							cout<<"0"<<endl;
    							return 0;
    						}
    						sort(a+1,a+1+n,greater<int>());
    						for(int i=1;i<n-1;i++) printf("%d",a[i]);
    						cout<<endl;
    						return 0;
    					}else if(i!=j && vis[i] && vis[j]){
    						for(int k=1;k<=n;k++)
    							if(a[k]==i){a[k]=0;break;}
    						for(int k=1;k<=n;k++)
    							if(a[k]==j){a[k]=0;break;}
    						sum-=i,sum-=j;
    						if(!sum){
    							cout<<"0"<<endl;
    							return 0;
    						}
    						sort(a+1,a+1+n,greater<int>());
    						for(int i=1;i<n-1;i++) printf("%d",a[i]);
    						cout<<endl;
    						return 0;
    					}
    				}
    	}
    	cout<<"-1"<<endl;
    	return 0;
    }
    

    【C Game】

      http://www.codeforces.com/contest/214/problem/C

      题目大意:有n个工作3台电脑,第i个工作需要在ci台电脑上完成。每一项工作还有很多“父工作”,必须在“父工作”都完成之后才能开始。工作花费1的时间,换电脑也需要时间,具体见题目描述,问最优策略的最短时间完成所有工作。

      乍一看是一个挺麻烦的DP题,仔细想想这就是坑爹啊……三台电脑1→2,2→3,3→1的时间都是1,而其他的移动时间是2,这就是说如果你想1→3,还不如1→2→3,后者还能捎带着把需要2号电脑的工作给做了。其他的移动同理。这点明白之后,这就变成一个贪心题,电脑由1→2→3→1→2的顺序不停轮换,能做的工作就做,枚举最开始的电脑就行了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    template<class T>inline void gmin(T &a,T b){if(a>b)a=b;}
    
    int n,k,x,c[201],map[201][201],deg[201],tmp[201],ans=2147483647;
    
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&c[i]);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&k);
    		while(k--){
    			scanf("%d",&x);
    			map[x][i]=1;
    			tmp[i]++;
    		}
    	}
    	for(int first_c=1;first_c<=3;first_c++){
    		int cur=first_c,rest=n,res=0;
    		memcpy(deg,tmp,sizeof(deg));
    		while(rest){
    			for(int k=1;k<=n;k++){
    				for(int i=1;i<=n;i++)
    					if(!deg[i] && c[i]==cur){
    						for(int j=1;j<=n;j++)
    							if(map[i][j]) deg[j]--;
    					deg[i]--,rest--;
    				}
    			}
    			cur=cur%3+1;
    			if(rest) res++;
    		}
    		gmin(ans,res);
    	}
    	ans+=n;
    	printf("%d\n",ans);
    	return 0;
    }
    

    【D Numbers】

      http://www.codeforces.com/contest/214/problem/D

      题目大意:(又是Furik和Rubik)给定n,给定数列a[],要求构造新数字满足:长度不超过n位,且数字i在新数字中出现至少a[i]次。问这样的数有多少个。

      比较简单的数位统计题,长度每增加一位,就插入一个数字,用组合数求。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    
    long long const BASE=1000000007ll;
    int n,a[11],sum;
    long long ans=0,f[11][101],C[101][101];
    
    long long dp(int x){
    	memset(f,0,sizeof(f));
    	f[0][0]=1;
    	for(int i=0;i<10;i++)
    		for(int j=0;j<=x;j++)
    			if(!f[i][j]) continue;
    			else
    				for(int k=a[i+1];k+j<=x;k++)
    					f[i+1][j+k]=(f[i+1][j+k]+f[i][j]*C[j+k][k])%BASE;
    	return f[10][x];
    }
    
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=10;i++){
    		scanf("%d",&a[i]);
    		sum+=a[i];
    	}
    	C[0][0]=1;
    	for(int i=1;i<=n;i++){
    		C[i][0]=1;
    		for(int j=1;j<=i;j++)
    			C[i][j]=(C[i-1][j]+C[i-1][j-1])%BASE;
    	}
    	for(int bit=max(1,sum);bit<=n;bit++){
    		if(bit==1) ans+=sum==1?1:9;
    		else{
    			for(int i=2;i<=10;i++){
    				int tmp=(a[i]!=0);
    				a[i]-=tmp;
    				ans=(ans+dp(bit-1))%BASE;
    				a[i]+=tmp;
    			}
    		}
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    【E Relay Race】

      http://www.codeforces.com/contest/214/problem/E

      题目大意:一个n×n的矩阵,找两条从(1,1)到(n,n)的路径使得权值和最大。每个格子权值只算一次,权值有负值。

      当时贴了个费用流完挂……大半夜的迷迷糊糊得没心思写了……

      不会的参考NOIP2000 提高组 方格取数

      f[k][i][j]表示走了k步,A在第i行,B在第j行,A、B的具体坐标可以由行数和步数推知,这样就压成了三维就过了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    
    int f[601][301][301],a[301][301],n;
    
    int max(int a,int b){
    	if(a>b) return a;
    	return b;
    }
    
    int gmax(int a,int b,int c,int d){
    	return max(max(max(a,b),c),d);
    }
    
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			scanf("%d",&a[i][j]);
    	memset(f,0xf3,sizeof(f));
    	f[1][1][1]=a[1][1];
    	for(int k=2;k<=n*2-1;k++)
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=n;j++)
    				f[k][i][j]=gmax(f[k-1][i][j],f[k-1][i][j-1],f[k-1][i-1][j],f[k-1][i-1][j-1]),
    				f[k][i][j]+=a[i][k-i+1]+(i==j?0:a[j][k-j+1]);
    	printf("%d\n",f[2*n-1][n][n]);
    	return 0;
    }
    
  • 相关阅读:
    动图+源码,演示 Java 中常用数据结构执行过程及原理
    16 个超级实用的 Java 工具类
    图解 Java 垃圾回收机制,写得非常好!
    一些值得收藏的开源框架
    JVM 发生内存溢出的 8 种原因、及解决办法
    VC的function类说明 -- 继续
    引用文章 如何在lambda中引入递归调用
    VC中function函数解析
    folly无锁队列正确性说明
    C++ Programming Language中的Calculator源代码
  • 原文地址:https://www.cnblogs.com/Delostik/p/2617051.html
Copyright © 2020-2023  润新知