说实话,今天的题真的很简单。
但是我……
50/0/0/100。
后来看看程序,发现是些很蠢的错误。。。还有没写的那些题,真的不难qwq
1.佳肴:
|
这道题就是暴!搜!但是我起始点输了1,结果本来到了最后一组数据,当做越界处理了……
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n; 4 int a[12],b[12],minans=1e9,ans[1000],tg[1000],cnt; 5 void dfs(int k,int mul,int sum,int tag){ 6 if(k>n) return; 7 ans[++cnt]=min(minans,abs(mul-sum)); 8 tg[cnt]=tag; 9 dfs(k+1,mul*a[k+1],sum+b[k+1],1); 10 dfs(k+1,mul,sum,tag); 11 } 12 int main(){ 13 scanf("%d",&n); 14 int oans=1e9; 15 for(int i=1;i<=n;i++){ 16 scanf("%d%d",&a[i],&b[i]); 17 oans=min(oans,abs(a[i]-b[i])); 18 } 19 dfs(0,1,0,0); 20 for(int i=1;i<=cnt;i++){ 21 if(!tg[i]) continue; 22 if(ans[i]<oans) oans=ans[i]; 23 } 24 printf("%d\n",oans); 25 return 0; 26 }
2.取数游戏
|
这道题很精妙,当你先取下一个数字后,剩下的数字就可以展开变成一个序列,每次都从序列的两边取,就变成区间dp了。
对于博弈论的题目,设置dp要考虑每个人都是天才,取到的都是最优解。
设s[i][j]表示区间中奇数个数,f[i][j]表示先手取i或j能获得的最大奇数个数,
f[i][j]=max(s[i][j]-f[i+1][j],s[i][j]-f[i][j-1]),转移方向从里到外,s用前缀和优化。
#include<bits/stdc++.h> using namespace std; const int N=110; int n; int a[N*2]; int s[N*2]; int f[N][N],ans; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i]&=1; } for(int i=1;i<=n;i++){ memset(f,0,sizeof(f)); memset(s,0,sizeof(s)); for(int j=1;j<=n;j++){ s[j]=s[j-1]+a[j]; f[j][j]=a[j]; } // for(int i=1;i<n;i++){ // for(int j=1;j+i<=n;j++){ // f[i][i+j]=max(s[i+j]-s[j-1]-f[j+1][i+j],s[i+j]-s[j-1]-f[j][i+j-1]); // } // } for(int k=1;k<=n-2;k++) { for(int j=1;j+k<=n;j++) { int l=k+j; f[j][l]=max(s[l]-s[j-1]-f[j+1][l],s[l]-s[j-1]-f[j][l-1]); } } // f[1][n]=s[n]-f[2][n]; if(s[n]/2+1<=f[1][n]) ans++; for(int i=0;i<=n;i++) a[i]=a[i+1]; a[n]=a[0]; } printf("%d\n",ans); // for(int i=1;i<=n;i++){ // for(int j=1;j+i<=n*2;j++){ // f[j][j+i-1]=max(s[j+i]-s[j-1]-f[j+1][j+i-1],s[j+i]-s[j-1]-f[j][j+i-2]); // } // } // for(int i=1;i<n;i++){ // for(int j=1;j+i<=n*2;j++){//l=j,r=j+i // f[j][j+i]=max(s[j+i]-s[j-1]-f[j+1][j+i],s[j+i]-s[j-1]-f[j][j+i-1]); // } // } // for(int k = 1;k <= n - 2;k++) { // for(int j = 1;j <= 2*n - k;j++) { // int l = k + j; // f[j][l]=max(s[l]-s[j-1]-f[j+1][l],s[l]-s[j-1]-f[j][l-1]); // } // } // for(int i=1;i<=2*n;i++){ // cout<<a[i]<<" "; // } // for(int i=1;i<=2*n;i++){ // cout<<s[i]<<" "; // } // for(int i=1;i<=n;i++){ // if(s[i+n-1]-s[i-1]-f[i+1][i+n-1]>(n>>1)) ans++; // } // printf("%d",ans); return 0; }
唯一一道不水的题目。
3.删除
这是道水题……但是当时没想到。
|
首先,对于一个表格,第二行和第三行不一定是全排列,就说明一定会有缺少的数字,我们用count记录一下。
不断遍历1~n,找到第一行有而第二行or第三行没有的数字,最重要的是把第一行的对应数字归零(这样就不会判断到它),然后对应得一列删除。
设置一个flag,判断每次删除情况,未删则跳出。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+10; 4 int n; 5 int ct1[N],ct2[N],ct3[N]; 6 int t2[N],t3[N],ans; 7 int main(){ 8 scanf("%d",&n); 9 for(int i=1;i<=n;i++){ 10 scanf("%d",&ct1[i]); 11 } 12 for(int i=1;i<=n;i++){ 13 scanf("%d",&ct2[i]); 14 t2[ct2[i]]++; 15 } 16 for(int i=1;i<=n;i++){ 17 scanf("%d",&ct3[i]); 18 t3[ct3[i]]++; 19 } 20 bool flag=false; 21 while(!flag){ 22 flag=true; 23 for(int i=1;i<=n;i++){ 24 if(ct1[i]&&!(t2[ct1[i]]&&t3[ct1[i]])){ 25 flag=false; 26 ct1[i]=0; 27 ans++; 28 t2[ct2[i]]--; 29 t3[ct3[i]]--; 30 } 31 } 32 } 33 printf("%d",ans); 34 return 0; 35 }
4.区间
|
这道题用了一点贪心的思想,我们将右端从大到小排序,这样遍历只用考虑左端点即可。
考虑包含关系,每一个左端点都要比上一个左端点大,所以就是找最长不下降子序列的问题了。
这里复习一下:
我们用len表示答案长度,或者说答案区间的长度,遍历数组,每测到一个新的值,就与答案数组的len位置比较,如果大于ans[len],则直接令ans[++len]=a[i],即更新答案长度,但是如果小于,则在答案数组中找到一个比这个数大的第一个数与之替换(因为本来也可以绕过那个数到达这个数,且不会影响答案)(这里使用upper_bound,注意返回的是地址,要减去初地址(如果是数组就减去数组名称)),然后没了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e6+10; 4 struct line{ 5 int l,r; 6 }a[N]; 7 int n,f[N]; 8 bool cmp(line t1,line t2){ 9 if(t1.r==t2.r) return t1.l<t2.l; 10 else return t1.r>t2.r; 11 } 12 int main(){ 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++){ 15 scanf("%d%d",&a[i].l,&a[i].r); 16 } 17 sort(a+1,a+n+1,cmp); 18 f[1]=a[1].l; 19 int len=1; 20 for(int i=2;i<=n;i++){ 21 if(a[i].l>=f[len]) f[++len]=a[i].l; 22 else{ 23 int j=upper_bound(f+1,f+len+1,a[i].l)-f; 24 f[j]=a[i].l; 25 } 26 } 27 printf("%d\n",len); 28 return 0; 29 }
总结:还是很菜,明天继续。