伊苏比的梦幻之旅(四)比赛题解
比赛地址:http://qscoj.cn/contest/28/
第13-1关 干部竞选(小数据)
分析:候选人的数量只有2,所以可以设置一个布尔变量f1表示学生投票后的胜者,f2表示全部将票投给学生1后的胜者,f3表示全部将票投给全胜2后的胜者;如果f1,f2,f3又不相同的情况的话,则说明老师投票对结果有影响,投票必须进行;如果三者相等则说明老师投票对结果没影响,投票无须进行。
标程:
#include<bits/stdc++.h> using namespace std; int main() { int n,m,a,b; bool f1,f2,f3; cin>>n>>m; cin>>a>>b; f1=(a>=b); f2=(a+m>=b); f3=(a>=b+m); if (f1==f2 && f2==f3) cout<<"No"<<endl; else cout<<"Yes"<<endl; return 0; }
第13-2关 干部竞选(中数据)
分析:候选人的数量只有8,老师的票数只有7;所以我们可以考虑所有的老师投票的情况,再判断对最后的排名结果有没有影响,只要有一组与之前的排名不同,则说明老师投票可以改变结果,必须进行。
标程:
#include<bits/stdc++.h> using namespace std; struct stu { int a,id; }p[10],q[10]; int n,m; bool flag; bool cmp(stu x,stu y) { if (x.a!=y.a) return x.a>y.a; return x.id<y.id; } void dfs(int k) { int i; if (k==m+1) { for(i=1;i<=n;i++) q[i]=p[i]; sort(q+1,q+1+n,cmp); for(i=1;i<=n;i++) if (q[i].id!=p[i].id) flag=false; return ; } for(i=1;i<=n;i++) { p[i].a++; dfs(k+1); p[i].a--; } } int main() { int i; cin>>n>>m; for(i=1;i<=n;i++) { p[i].id=i; cin>>p[i].a; } sort(p+1,p+1+n,cmp); flag=true;dfs(1); if (flag) cout<<"No"<<endl; else cout<<"Yes"<<endl; return 0; }
第13-3关 干部竞选(大数据)
分析:因为本题要求只要一名同学的票数可能发生变化,老师投票就应该进行。所以我们可以先把所有候选人进行完学生投票后排个序,再依次判断第2个人能不能超过第1个,第3个能不能超过第2个,第N个能不能超过第N-1个,这些只要有一个满足就应进行老师投票,否则则不必。
标程:
#include<bits/stdc++.h> using namespace std; struct stu { int a,id; }p[100010]; bool cmp(stu x,stu y) { if (x.a!=y.a) return x.a>y.a; return x.id<y.id; } int main() { int n,m,i; bool flag; cin>>n>>m; for(i=1;i<=n;i++) { p[i].id=i; scanf("%d",&p[i].a); } sort(p+1,p+1+n,cmp);flag=true; for(i=2;i<=n;i++) { p[i].a+=m; if (p[i].a>p[i-1].a) flag=false; if (p[i].a==p[i-1].a && p[i].id<p[i-1].id) flag=false; p[i].a-=m; } if (flag) cout<<"No"<<endl; else cout<<"Yes"<<endl; return 0; }
第14-1关 男女搭配(小数据)
分析:N的范围只有2,为1时答案就为g(1)*l(1);为2时判断下g(1)*l(1)+g(2)*l(2)和g(1)*l(2)+g(2)*l(1)哪个大就好。
标程:
#include<bits/stdc++.h> using namespace std; int main() { int n,i,ans1,ans2,ans; int g[3],l[3]; cin>>n; for(i=1;i<=n;i++) cin>>g[i]; for(i=1;i<=n;i++) cin>>l[i]; if (n==1) ans=g[1]*l[1]; else { ans1=g[1]*l[1]+g[2]*l[2]; ans2=g[1]*l[2]+g[2]*l[1]; ans=max(ans1,ans2); } cout<<ans<<endl; return 0; }
第14-2关 男女搭配(中数据)
分析:N的范围只有10,所以配对方式共有10!=3628800种情况,我们可以放N个位置,保持男生的位置不变,通过next_permutation函数使女生的位置发生变化,然后从所有情况中取最大值就行。
标程:
#include<bits/stdc++.h> using namespace std; int main() { int l[12],g[12],a[12]; int res,ans,n,i; cin>>n;ans=0; for(i=1;i<=n;i++) cin>>l[i]; for(i=1;i<=n;i++) cin>>g[i]; for(i=1;i<=n;i++) a[i]=i; do { res=0; for(i=1;i<=n;i++) res+=l[i]*g[a[i]]; ans=max(res,ans); }while(next_permutation(a+1,a+1+n)); cout<<ans<<endl; return 0; }
第14-3关 男女搭配(大数据)
分析:如果我们先把男生的绅士度从大到小排个序,再给男生选择配对的女生的时候,按照贪心的思想,较大绅士度的男生肯定应该搭配较大可爱度的女生,才能使总和最大。所以也应该将女生从大到小排个序,再将对应位置的男生女生进行配对,一定是最优解。注意一个问题,N的范围为1000,g(i)、l(j)的范围为10^8,总和最大可能达到10^19,超过了long long的范围,所以应该使用unsigned long long.
标程:
#include<bits/stdc++.h> using namespace std; unsigned long long l[100010],g[100010]; int main() { int i,n; unsigned long long ans; cin>>n;ans=0; for(i=1;i<=n;i++) scanf("%llu",&l[i]); for(i=1;i<=n;i++) scanf("%llu",&g[i]); sort(l+1,l+1+n); sort(g+1,g+1+n); for(i=1;i<=n;i++) ans+=l[i]*g[i]; cout<<ans<<endl; return 0; }
第15-1关 外国人排队(小数据)
分析:这个问题考虑时我们应该先将每个位置放哪国人的方案数算出来再乘上各个国家在自己国家应在的位置上的全排列数。如果只有两个国家的人的话两个国家的人数相差不能超过1,如果相差为1,只有ABABABABA这一种情况;如果相等,则有ABABABAB和BABABABA两种情况。再乘上两个国家人数的阶乘就是所求答案。
标程:
#include<bits/stdc++.h> using namespace std; int main() { int i,a,b,c,ans; int jc[8]; jc[0]=1; for(i=1;i<=7;i++) jc[i]=jc[i-1]*i; cin>>a>>b>>c; if (a==b) ans=2*jc[a]*jc[b]; else if (abs(a-b)<=1) ans=jc[a]*jc[b]; else ans=0; cout<<ans<<endl; return 0; }
第15-2关 外国人排队(中数据)
分析:人数总数不会超过21个,当我们确定了某个位置人的国籍后,下一个人的国籍最多有两种情况,所以采用DFS的方法是3*2^20的复杂度。通过DFS的方式将每个位置是什么国家人的方案数求出来,再乘以各个国家内部的全排列数就是答案。
标程:
#include<bits/stdc++.h> using namespace std; int c1,c2,c3; int p[23]; int a,b,c,s; long long ans; int mod=1e9+7; void dfs(int k) { int i; if (k==s+1) { if (c1==a && c2==b && c3==c) ans++; return ; } for(i=1;i<=3;i++) { if (i==p[k-1]) continue; p[k]=i; if (i==1) {c1++;dfs(k+1);c1--;} if (i==2) {c2++;dfs(k+1);c2--;} if (i==3) {c3++;dfs(k+1);c3--;} } } int main() { int jc[8],i; jc[0]=1; for(i=1;i<=7;i++) jc[i]=jc[i-1]*i; cin>>a>>b>>c;ans=0;s=a+b+c; dfs(1); ans*=jc[a];ans%=mod; ans*=jc[b];ans%=mod; ans*=jc[c];ans%=mod; cout<<ans<<endl; return 0; }
第15-3关 外国人排队(大数据)
分析:N的范围为77,肯定不能采用像第15-2关那样用DFS的方式去做,应用DP的方式进行转移。我们设置一个四维的DP,DP[i][j][k][x]表示当前有i个美国人,j个英国人和k个美国人且最后一位为x国的方案数;x为1代表美国人,为2代表英国人,为3代表法国人。因为任意两个相邻位置的人都不能是相同国家的,因此DP[i][j][k][1]可以从DP[i-1][j][k][2]和DP[i-1][j][k][3]转移而来;DP[i][j][k][2]可以从DP[i][j-1][k][1]和DP[i][j-1][k][3]转移而来;DP[i][j][k][3]可以从DP[i][j][k-1][1]和DP[i][j][k-1][2]转移而来。最后的答案就是DP[a][b][c][1]+DP[a][b][c][2]+DP[a][b][c][3].
标程:
#include<bits/stdc++.h> using namespace std; long long dp[80][80][80][4]; long long mod=1e9+7; int main() { int a,b,c,s; int i,j,k,r; long long jc[80],ans; cin>>a>>b>>c;s=a+b+c; for(r=1;r<=s;r++) { for(i=0;i<=a;i++) for(j=0;j<=b;j++) { k=r-i-j; if (k<0 || k>c) continue; if (i) { if (r==1 && j+k==0) {dp[i][j][k][1]=1;continue;} dp[i][j][k][1]+=dp[i-1][j][k][2];dp[i][j][k][1]%=mod; dp[i][j][k][1]+=dp[i-1][j][k][3];dp[i][j][k][1]%=mod; } if (j) { if (r==1 && k+i==0) {dp[i][j][k][2]=1;continue;} dp[i][j][k][2]+=dp[i][j-1][k][1];dp[i][j][k][2]%=mod; dp[i][j][k][2]+=dp[i][j-1][k][3];dp[i][j][k][2]%=mod; } if (k) { if (r==1 && i+j==0) {dp[i][j][k][3]=1;continue;} dp[i][j][k][3]+=dp[i][j][k-1][1];dp[i][j][k][3]%=mod; dp[i][j][k][3]+=dp[i][j][k-1][2];dp[i][j][k][3]%=mod; } } } ans=dp[a][b][c][1]+dp[a][b][c][2]+dp[a][b][c][3];ans%=mod; jc[0]=1; for(i=1;i<=77;i++) { jc[i]=jc[i-1]*i; jc[i]%=mod; } ans*=jc[a];ans%=mod; ans*=jc[b];ans%=mod; ans*=jc[c];ans%=mod; cout<<ans<<endl; return 0; }