写在前面,这场比赛是这个暑假最后一场多校比赛了,打得很不好,特别是在杭电的比赛,总是感觉水土不服一样。感觉自己比赛的时候总喜欢看榜,怎么说呢,看榜有看榜的好处吧,但是感觉在牛客和杭电的几场比赛都被榜带偏了,赛后补题的时候我觉得这题我是可以做出来的。说这么多,关键还是自己的比赛时的心态有问题,别一天天的盯着榜看,我觉得以后也要改正一下比赛时看榜的习惯了(或者说以后坚决不看榜),会做的总会做,不会做的看一辈子还是那样。
Mine Sweeper
题意:给出一个数s,构造出一个类似于扫雷游戏那种的矩阵,使得矩阵中所有数字之和为s。
思路:这题其实比赛时的思路已经很接近了,只是还是想复杂了一些,与官方题解的思路想到过一样的,但很快就想当然的否决了。这个题目其实如果用wps的表格进行模拟的话我觉得效果会更好。首先,当s<25的时候,我们就可以构造出X.X.X.X.类似这种的一行的矩阵出来,当s>25的时候,我们先这样考虑,对于一个完整的九宫格的话,我们只要在中心位置加上一个X,就相当于造成了增加8的贡献,
即使最大到1000的话我们也只需要125个这样的九宫格。如果构造完整的25X25的矩阵的话,那么就可以构造出12X12=144个这种的九宫格,这显然是够的,所以我们就看输入的s中有几个8,然后就构造出几个九宫格就行了,对于余数的情况,我们只要适当的添加一些X进去就行了。最后我们可以证明到不管s为多少我们都有最终的答案。
对于余数的情况,只要看代码,然后再用wps表格验证一下就行了,其实方法有很多。
代码:
#include<bits/stdc++.h> using namespace std; char c[30][30]; char b[30]; int s; void deal1(){ for(int i=1;i<=25;i++){ if(i&1) b[i]='X'; else b[i]='.'; } cout<<"1 "<<s+1<<endl; for(int i=1;i<=s+1;i++){ cout<<b[i]; } cout<<endl; } void deal2(){ int k1=s/8; int k2=s%8; int x=2,y=2; while(k1>0){ c[x][y]='X'; y+=2; if(y>24){ x+=2; y=2; } k1--; } //对余数进行处理 if(k2==1) c[1][1]='X'; if(k2==2) c[1][1]=c[1][2]='X'; if(k2==3) c[1][2]='X'; if(k2==4) c[2][3]='X'; if(k2==5) c[1][1]=c[2][3]='X'; if(k2==6) c[25][25]=c[25][24]='X'; if(k2==7) c[1][1]=c[25][25]=c[25][24]='X'; cout<<"25 25"<<endl; for(int i=1;i<=25;i++){ for(int j=1;j<=25;j++){ cout<<c[i][j]; } cout<<endl; } } int main(){ int t; cin>>t; while(t--){ for(int i=1;i<=25;i++){ for(int j=1;j<=25;j++){ c[i][j]='.'; } } cin>>s; if(s<25){ deal1(); } else deal2(); } return 0; }
Permutation Counting
题意:这题有点cf的味道,给你一个长为n-1的01序列,表示的是1-n这n个数的某种排列,如果,那么第i个位置就是0,否则就是1,要求求出符合条件的构造情况有多少种?
思路:看了题解后还是一头雾水,怎么想到的这种的构造方法的?
可能是目前能力还没达到那种高度吧,把题解先贴在这里,希望以后能回来搞懂。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e9+7; ll res; int a[5010]; ll dp[5010][5010]; void solve(){ int n; cin>>n; for(int i=1;i<n;i++) cin>>a[i]; memset(dp,0,sizeof(dp)); dp[1][1]=1; if(a[1]) dp[2][1]=1; else dp[2][2]=1; for(int i=2;i<n;i++){ if(a[i]){ for(int j=i;j;j--){ dp[i+1][j]=(dp[i+1][j+1]+dp[i][j])%mod; } } else{ for(int j=2;j<=i+1;j++){ dp[i+1][j]=(dp[i][j-1]+dp[i+1][j-1])%mod; } } } res=0; for(int i=1;i<=n;i++) res=(res+dp[n][i])%mod; cout<<res<<endl; } int main(){ int t; cin>>t; while(t--){ solve(); } return 0; }
Task Scheduler
题意:最开始开的就是这道题目,我觉得这道题目才是签到题,但后面看榜的时候发现这道题目过的人不多,以为有什么大坑,在加上题目有点没搞懂什么意思。所以跑去开其他题了,后面队友又在开这道题我就没看了。。。
这题就是有n个任务,每个任务需要ti名工人去做,其中有m个工人,这m个工人之中又有k个工人是与这种任务无关的,(也就是只有m-k个工人派去做任务才有用)。然后要求求出n个任务的一种完成顺序,使得派遣工人的次数最少。题目保证工人的完成人数是够的,也就是肯定存在一种方案使得可以完成所有的工作。同时答案要保证序列的字典序最小。
思路:贪心。首先,我们先考虑k=0的情况,这种是有点难想到的,如果k=0的话,我们直接输出1-n即可,如果k!=0的话,我们为了选工人的时候能够提高完成任务的概率(有可能选了比较多的k个无关工人中的人),我们肯定是要确保在选人尽量选到有关的工人,所以我们只需要对每个任务所需要的工人的数量进行排序,从多到少进行分配即可。因为在分式当中,当分子比分母小的情况下,分母和分子减少相同数的情况下,分数的大小会变得更小。也就是越到后面,就难选到有关的工人,而你如果选的越多的话,就更难选到满足任务所需的工人了。
#include<bits/stdc++.h> using namespace std; struct node{ int val; int index; }Node[110]; bool cmp(node a,node b){ if(a.val!=b.val) return a.val>b.val; return a.index<b.index; } void solve(){ int n,m,k; cin>>n>>m>>k; for(int i=1;i<=n;i++){ cin>>Node[i].val; Node[i].index=i; } if(k) sort(Node+1,Node+1+n,cmp); for(int i=1;i<=n;i++){ cout<<Node[i].index; if(i<n) cout<<" "; } cout<<endl; } int main(){ int t; cin>>t; while(t--){ solve(); } return 0; }