插头DP智障操作合集

今天一共四道插头DP【其实都差不多】,智障错误出了不下五个:D

来,让我好好数落我自己一下

直接写代码注释里吧

Eat the Trees

#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];//变量名打错过,打成了plag…虽然这个并不是很重要
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【这是个伏笔】 

P2289 [HNOI2004]邮递员

#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;
}

今天也在非常认真地怀疑自己的智商

猜你喜欢

转载自www.cnblogs.com/chloris/p/11260955.html