插头DP智障操作合集
今天一共四道插头DP【其实都差不多】,智障错误出了不下五个:D
来,让我好好数落我自己一下
直接写代码注释里吧
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int t,n,m; int a[15][15],sit[15]; long long f[15][15][(1<<15)+10];//忘开long long几百次 void clear(){ memset(f,0,sizeof(f)); memset(a,0,sizeof(a)); } void work(int x,int y){ int plug1=sit[y-1],plug2=sit[y]; for(int i=0;i<sit[m+1];i++){ if(a[x][y]){ f[x][y][i]+=f[x][y-1][i^plug1^plug2]; if(((i>>y-1)&1)==((i>>y)&1))continue; f[x][y][i]+=f[x][y-1][i]; } else{ if(!(i&plug1)&&!(i&plug2))f[x][y][i]=f[x][y-1][i]; else f[x][y][i]=0; } } } int main() { scanf("%d",&t); sit[0]=1; for(int i=1;i<=15;i++)sit[i]=sit[i-1]<<1; while(t--){ clear(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); } } f[1][0][0]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ work(i,j); } if(i!=n){ for(int j=0;j<sit[m];j++){ f[i+1][0][j<<1]=f[i][m][j]; } } } printf("%lld\n",f[n][m][0]); } return 0; } //第一篇几乎是对着前辈的代码打的 大概没什么问题 【虽然本质应该是背着打然后对着改】
Ural 1519 Formula 1
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m,e1,e2,las,now,tt; const int has=299989; int sit[15],a[2][300005],mp[15][15],head[300005],Next[300005],tot[2]; long long f[2][300005],ans; char c[15]; void ins(int zt,long long num){ int pos=zt%has+1; for(int i=head[pos];i;i=Next[i]){ if(a[now][i]==zt){ f[now][i]+=num; return; } } Next[++tot[now]]=head[pos],head[pos]=tot[now]; a[now][tot[now]]=zt,f[now][tot[now]]=num; } void work(){ tot[now]=1,f[now][1]=1,a[now][1]=0; for(int i=1;i<=n;i++){ for(int j=1;j<=tot[now];j++)a[now][j]<<=2; for(int j=1;j<=m;j++){ las=now,now^=1; memset(head,0,sizeof(head)); tot[now]=0; for(int k=1;k<=tot[las];k++){ int zt=a[las][k],b1=((zt>>((j-1)*2))%4),b2=((zt>>(j*2))%4); long long num=f[las][k]; if(!mp[i][j]){ if(!b1&&!b2)ins(zt,num); } else if(!b1&&!b2){ if(mp[i+1][j]&&mp[i][j+1])ins(zt+sit[j-1]+2*sit[j],num); } else if(b1&&!b2){ if(mp[i][j+1])ins(zt-sit[j-1]*b1+sit[j]*b1,num); if(mp[i+1][j])ins(zt,num); } else if(!b1&&b2){ if(mp[i+1][j])ins(zt-sit[j]*b2+sit[j-1]*b2,num); if(mp[i][j+1])ins(zt,num); } else if(b1==1&&b2==1){ int kl=1; for(int t=j+1;t<=m;t++){ if((zt>>(t*2))%4==1)kl++; if((zt>>(t*2))%4==2)kl--; if(!kl){ ins(zt-sit[j-1]-sit[j]-sit[t],num); break; } } } else if(b1==2&&b2==2){ int kl=1; for(int t=j-2;t>0;t--){ if((zt>>(t*2))%4==1)kl--; if((zt>>(t*2))%4==2)kl++; if(!kl){ ins(zt+sit[t]-2*sit[j-1]-2*sit[j],num); break; } } } else if(b1==2&&b2==1){ ins(zt-2*sit[j-1]-sit[j],num); } else if(i==e1&&j==e2)ans+=num; } } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%s",c+1); for(int j=1;j<=m;j++){ if(c[j]=='.')mp[i][j]=1,e1=i,e2=j; } } sit[0]=1; for(int i=1;i<=12;i++){ sit[i]=(sit[i-1]<<2); } work(); printf("%lld\n",ans); return 0; } //其实也是背着写了一遍再对着标程改…这一篇是一次AC【这是个伏笔】
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int m,n,now,lst; const int has=299989; int sit[12],a[2][300010],head[300010],Next[300010],tot[2]; struct node{ int len; int c[50]; }f[2][300010],ans; node jia(node a,node b){ node d; int sum=0; memset(d.c,0,sizeof(d.c)); d.len=max(a.len,b.len); for(int i=1;i<=d.len;i++){ sum=sum+a.c[i]+b.c[i]; d.c[i]=sum%10; sum/=10; } while(sum){ d.c[++d.len]=sum%10; sum/=10; } return d; } void ins(int zt,node num){ int pos=zt%has+1; for(int i=head[pos];i;i=Next[i]){ if(a[now][i]==zt){ f[now][i]=jia(f[now][i],num);//这个地方写成了jia(f[now][i],num) //对,不是f[now][i]=jia(f[now][i],num)…只写了调用函数没有赋值…还以为是高精炸了 return; } } Next[++tot[now]]=head[pos],head[pos]=tot[now]; a[now][tot[now]]=zt,f[now][tot[now]]=num; } void work(){ memset(f[now][1].c,0,sizeof(f[now][1].c)); tot[now]=1,a[now][1]=0,f[now][1].len=1,f[now][1].c[1]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=tot[now];j++)a[now][j]<<=2; for(int j=1;j<=m;j++){ lst=now,now^=1; memset(head,0,sizeof(head)); tot[now]=0; for(int k=1;k<=tot[lst];k++){ node num=f[lst][k]; int zt=a[lst][k]; int b1=((zt>>(j-1)*2))%4,b2=(zt>>(j*2))%4; if(!b1&&!b2){ if(j+1<=m&&i+1<=n)ins(zt+sit[j-1]+sit[j]*2,num); } else if(!b1&&b2){ if(j+1<=m)ins(zt,num); if(i+1<=n)ins(zt-sit[j]*b2+sit[j-1]*b2,num); } else if(b1&&!b2){ if(i+1<=n)ins(zt,num); if(j+1<=m)ins(zt-sit[j-1]*b1+sit[j]*b1,num); } else if(b1==1&&b2==1){ int kl=1; for(int t=j+1;t<=m;t++){ if((zt>>(t*2))%4==1)kl++; if((zt>>(t*2))%4==2)kl--; if(!kl){ ins(zt-sit[j]-sit[j-1]-sit[t],num); break; } } } else if(b1==2&&b2==2){ int kl=1; for(int t=j-2;t>0;t--){//写成j-1一万次…… if((zt>>(t*2))%4==1)kl--; if((zt>>(t*2))%4==2)kl++; if(!kl){ ins(zt-sit[j]*2-sit[j-1]*2+sit[t],num); break; } } } else if(b1==2&&b2==1){ ins(zt-sit[j-1]*2-sit[j],num); } else if(i==n&&j==m)ans=jia(ans,num); } } } } int main() { scanf("%d%d",&m,&n); if(m==1||n==1){//这个特判,一开始打成m==1||n==1 输出0…然后折腾了半天想路径长度去了【?】 然后写成了m==1&&n==1 输出1… printf("1"); return 0; } sit[0]=1; for(int i=1;i<=11;i++)sit[i]=(sit[i-1]<<2);//一开始跑了n的范围,20,还没意识到炸了…被提醒以后第一反应居然是开long long而不是转成m的范围 work(); ans=jia(ans,ans); if(!ans.len){ printf("0"); return 0; } for(int i=ans.len;i>=1;i--){ printf("%d",ans.c[i]); } return 0; }
CITY
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m,now,lst,e1,e2; const int has=299989; long long ans,f[2][300010]; int a[2][300010],tot[2],Next[300010],head[300010],sit[15]; char mp[15][15],s[15]; void ins(int zt,long long num){ int pos=zt%has+1; for(int i=head[pos];i;i=Next[i]){ if(a[now][i]==zt){ f[now][i]+=num; return; } } Next[++tot[now]]=head[pos],head[pos]=tot[now]; a[now][tot[now]]=zt,f[now][tot[now]]=num; } void work(){ tot[now]=1,a[now][1]=0,f[now][1]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=tot[now];j++)a[now][j]<<=2; for(int j=1;j<=m;j++){ lst=now,now^=1; memset(head,0,sizeof(head)); tot[now]=0; for(int k=1;k<=tot[lst];k++){ long long num=f[lst][k]; int zt=a[lst][k],b1=(zt>>((j-1)*2))%4,b2=(zt>>(j*2))%4; if(mp[i][j]=='#'){ if(!b1&&!b2)ins(zt,num); } else if(!b1&&!b2){ if(mp[i][j]=='.'&&(mp[i+1][j]=='|'||mp[i+1][j]=='.')&&(mp[i][j+1]=='-'||mp[i][j+1]=='.')){ ins(zt+sit[j-1]+sit[j]*2,num); } } else if(b1&&!b2){ if((mp[i+1][j]=='.'||mp[i+1][j]=='|')&&mp[i][j]!='-'&&mp[i][j]!='|')ins(zt,num); if((mp[i][j+1]=='.'||mp[i][j+1]=='-')&&mp[i][j]!='|')ins(zt-sit[j-1]*b1+sit[j]*b1,num); } else if(!b1&&b2){ if((mp[i][j+1]=='.'||mp[i][j+1]=='-')&&mp[i][j]!='-'&&mp[i][j]!='|')ins(zt,num); if((mp[i+1][j]=='.'||mp[i+1][j]=='|')&&mp[i][j]!='-')ins(zt-sit[j]*b2+sit[j-1]*b2,num); } else if(b1==1&&b2==1){ if(mp[i][j]!='-'&&mp[i][j]!='|'){ int kl=1; for(int t=j+1;t<=m;t++){ if((zt>>(t*2))%4==1)kl++; if((zt>>(t*2))%4==2)kl--; if(!kl){ ins(zt-sit[j]-sit[j-1]-sit[t],num); break; } } } } else if(b1==2&&b2==2){ if(mp[i][j]!='-'&&mp[i][j]!='|'){ int kl=1; for(int t=j-2;t>0;t--){ if((zt>>(t*2))%4==1)kl--; if((zt>>(t*2))%4==2)kl++; if(!kl){ ins(zt-sit[j]*2-sit[j-1]*2+sit[t],num); break; } } } } else if(b1==2&&b2==1){ if(mp[i][j]!='-'&&mp[i][j]!='|'){ ins(zt-sit[j-1]*2-sit[j],num); } } else if(i==e1&&j==e2&&mp[i][j]!='-'&&mp[i][j]!='|'){//伏笔还是要收的,久等了【大雾】 // 上一道题没有用到e1e2,第二道题我又是照着标程改的,然后完美忘记,从(n,m)的地方累计答案去了 //居然还有90分,折腾了半天细节,结果是这里… ans+=num; } } } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%s",s+1); for(int j=1;j<=m;j++){ mp[i][j]=s[j]; if(j==1||j==m){ if(mp[i][j]=='-'){ printf("0"); return 0; } } if(i==1||i==n){ if(mp[i][j]=='|'){ printf("0"); return 0; } } if(mp[i][j]!='#')e1=i,e2=j;//伏 笔 回 收 ,欠下的总是要还的 } } sit[0]=1; for(int i=1;i<=13;i++)sit[i]=sit[i-1]<<2; work(); printf("%lld",ans); return 0; }
今天也在非常认真地怀疑自己的智商