2017 8 15 得分:15
爆零快乐~
A、字符合并
链接:http://cogs.pro/cogs/problem/problem.php?pid=2269
题意:每个一定长度$0-1$串可以转化成一个二进制数字求出一个$0-1$串转化。
考试时第一遍集体爆零……最后发现测试点还是$HAOI2016$锅了的测试点……
正解是状压……写的很详细的代码注释……自己取吧……
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=305,maxa=1<<9; 7 long long f[maxn][maxn][2],c[maxn],v[maxn],a[maxn],g[maxn][maxa],now,tmp[3],ans[maxn]; 8 /*我们这里的f数组与其他的f数组并不完全相同,这里的f数组第三维严格地讲只是半维,0/1表示这个串全部变为0/1可以获得的最大积分; 9 相应的g数组第二维从半维变成整维,第二维代替了f数组本应该存在的存储最近8位状态的第三维,g数组也就改变了意义,g[i][j]变为转移到i这个长度,最后几位状态为j下最大收益; 10 然后,这个tmp数组中的tmp[i]也就表示了所有可以转化到i的01串转化后连带前面的串可以获得的最大收益。*/ 11 int N,K; 12 int haha() 13 { 14 //freopen("merge_2016.in","r",stdin); 15 //freopen("merge_2016.out","w",stdout); 16 scanf("%d%d",&N,&K);//输入 17 int att=(1<<K);//确定最大状态 18 memset(f,-1,sizeof(f));//初始化记忆化表格 19 for(int i=1;i<=N;i++)//输入01串 20 { 21 scanf("%1d",&a[i]); 22 f[i][i][a[i]]=0;//已经合适,就不需要修改 23 } 24 for(int i=0;i<att;i++)scanf("%d%d",&c[i],&v[i]);//每一种修改的情况 25 for(int i=N-K+1;i>=1;i--)//可以搞这么多轮,从后往前合并 26 { 27 memset(g,-1,sizeof(g));//初始化 28 now=1;g[i][0]=f[i][i][0];g[i][1]=f[i][i][1];//从i开始的串最后一位状态为0、1的情况已经确定了 29 for(int j=i+1;j<=N;j++) 30 { 31 for(int s=0;s<(1<<now);s++)//枚举状态 32 if(g[j-1][s]>=0)//这一状态是合法的 33 for(int k=j;k<=N;k+=K-1)//每k个为一段判断 34 { 35 if(f[j][k][0]>=0)g[k][s<<1]=max(g[k][s<<1],g[j-1][s]+f[j][k][0]);//可以合成0就合成0 36 if(f[j][k][1]>=0)g[k][s<<1|1]=max(g[k][s<<1|1],g[j-1][s]+f[j][k][1]);//可以合成1就合成1,其实这里就是一个区间dp 37 } 38 if(++now==K)//长度够了 39 { 40 tmp[0]=tmp[1]=-1;//初始化转化到尾巴的情况 41 for(int k=0;k<(1<<now);k++) 42 if(g[j][k]>=0)tmp[c[k]]=max(tmp[c[k]],v[k]+g[j][k]);//这个状态是可以构建出来的,就更新以目标字符结尾的结果 43 f[i][j][1]=g[j][1]=tmp[1];//更新结果 44 f[i][j][0]=g[j][0]=tmp[0]; 45 now=1; 46 } 47 } 48 } 49 for(int i=1;i<=N;i++) 50 for(int j=i;j<=N;j+=K-1)ans[j]=max(ans[j],ans[i-1]+max(f[i][j][1],f[i][j][0]));//每一个都可以合并,能合就合 51 printf("%lld ",ans[N]); 52 } 53 int sb=haha(); 54 int main(){;}
B、就
题意:给出一个填了一部分的矩阵,问存不存在非负整数填法使得每个$2*2$子矩阵满足左上加右下等于右上加左下。
考试只得了$10$分特判……
我们差分一下就可以发现:每一列差相等。于是我们就可以维护带权并查集,竖着一组横着一组……然后判断差分合不合法、最小解是否非负即可……
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int maxn=100005; 7 int fa[maxn],fa2[maxn];long long w1[maxn],w2[maxn]; 8 struct node 9 { 10 int x,y,val; 11 void read() 12 { 13 scanf("%d%d%d",&x,&y,&val); 14 } 15 }P[maxn]; 16 bool cmpx(const node &a,const node &b) 17 { 18 return a.x<b.x; 19 } 20 bool cmpy(const node &a,const node &b) 21 { 22 return a.y<b.y; 23 } 24 int getfa1(int x) 25 { 26 if(x==fa[x])return x; 27 int rt=getfa(fa[x]);w1[x]+=w1[fa[x]];return fa[x]=rt; 28 } 29 int getfa2(int x) 30 { 31 if(x==fa2[x])return x; 32 int rt=getfa2(fa2[x]);w2[x]+=w2[fa2[x]];return fa2[x]=rt; 33 } 34 bool unionn1(int a,int b,long long w) 35 { 36 if(getfa1(a)!=getfa1(b)) 37 { 38 a=getfa1(a),b=getfa1(b); 39 fa[a]=fa[b];w1[a]=w+w1[b]-w1[a]; 40 return 1; 41 } 42 else return w1[a]==w+w1[b]; 43 } 44 bool unionn2(int a,int b,long long w) 45 { 46 if(getfa2(a)!=getfa2(b)) 47 { 48 a=getfa2(a),b=getfa2(b); 49 fa2[a]=fa2[b];w2[a]=w+w2[b]-w2[a]; 50 return 1; 51 } 52 else return w2[a]==w+w2[b]; 53 } 54 long long min1[maxn],min2[maxn]; 55 int haha() 56 { 57 freopen("then.in","r",stdin); 58 freopen("then.out","w",stdout); 59 int tests;scanf("%d",&tests); 60 while(tests--) 61 { 62 bool tt=1; 63 int r,c;scanf("%d%d",&r,&c); 64 for(int i=1;i<=r;i++)fa[i]=i,w1[i]=0; 65 for(int i=1;i<=c;i++)fa2[i]=i,w2[i]=0; 66 int n;scanf("%d",&n); 67 for(int i=1;i<=n;i++)P[i].read(); 68 for(int i=1;i<=n;i++)if(P[i].val<0)tt=0; 69 sort(P+1,P+n+1,cmpx); 70 for(int i=1;i<n;i++) 71 if(P[i].x==P[i+1].x) 72 if(!unionn2(P[i].y,P[i+1].y,P[i+1].val-P[i].val))tt=0; 73 sort(P+1,P+n+1,cmpy); 74 for(int i=1;i<n;i++) 75 if(P[i].y==P[i+1].y) 76 if(!unionn1(P[i].x,P[i+1].x,P[i+1].val-P[i].val))tt=0; 77 memset(min1,0x3f,sizeof(min1)); 78 memset(min2,0x3f,sizeof(min2)); 79 for(int i=1;i<=n;i++) 80 { 81 int rt=getfa1(P[i].x); 82 min1[rt]=min(min1[rt],P[i].val+w1[P[i].x]); 83 } 84 for(int i=1;i<=r;i++) 85 { 86 int rt=getfa1(i); 87 min2[rt]=min(min2[rt],-w1[i]); 88 } 89 for(int i=1;i<=r;i++) 90 if(fa[i]==i&&min1[i]+min2[i]<0)tt=0; 91 if(tt==1)puts("Yes");else puts("No"); 92 } 93 } 94 int sb=haha(); 95 int main(){;}
C、做
题意:使魔法伤害为两点欧几里得距离平方,每次曼哈顿距离可以减少$2$求被干的人使用最优策略会不会死。
日常爆零……
然后发现自己本来可以$A$的= =就是个大模拟……
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<ctime> 7 using namespace std; 8 const int maxn=305,maxh=205; 9 long long f[maxn][maxn][maxh]; 10 void change(int &x,int &y) 11 { 12 int dis1=2*(x+y)-2,dis2=4*x-4,dis3=4*y-4; 13 int dis=max(dis1,max(dis2,dis3)); 14 if(dis==dis1)x--,y--;else if(dis==dis2)x-=2;else y-=2; 15 } 16 int haha() 17 { 18 //freopen("do3.in","r",stdin); 19 //freopen("do.out","w",stdout); 20 int t,a,b;scanf("%d",&t);scanf("%d%d",&a,&b); 21 while(t--) 22 { 23 int x1,y1,x2,y2,c;long long d;scanf("%d%d%d%d%d%lld",&x1,&y1,&x2,&y2,&c,&d); 24 x2-=x1;y2-=y1;x2=abs(x2);y2=abs(y2);int dis=x2+y2; 25 while(dis>0&&d>=0) 26 { 27 if(c>=a)d-=y2*y2+x2*x2,c-=a;else c+=b; 28 dis-=2; 29 change(x2,y2); 30 if(d<=0)break; 31 } 32 if(d<=0)puts("NAIVE"); 33 else puts("SIMPLE"); 34 } 35 } 36 int sb=haha(); 37 int main(){;}