標籤:pac style continue family 沒有 mem cpp 需要 i++
感覺get到了一種數位dp的新姿勢,加一位表示當前要填的數有沒有限制(感覺以前的寫法都太蠢了).
這麼寫有兩個地方要注意:
1.每dp到一位時需要f[i][初始狀態]++,相當於這位前都是前置字元為零(這道題我把前兩位填了兩個10作為初始狀態)。
2.因為有了1,所以初始狀態後的第一位不能填0,需要特判
f[i][j][k][l][p][q][o]表示填到第幾位,上上位和上位分別是什麼,4,8是否出現過,三個連續的是否出現過,以及當前位是否有限制。
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define ll long longusing namespace std;ll pw[100];ll f[20][11][11][2][2][2][2];// 位元 上位 這位 4 8 出現0/1 限制0/1 ll solve(ll x){pw[0]=1;for(int i=1;i<=12;i++)pw[i]=pw[i-1]*10;int pos;for(int i=0;i<=12;i++)if(x>=pw[i])pos=i+1;memset(f,0,sizeof(f));f[0][10][10][0][0][0][1]=1;for(int i=1;i<=pos;i++){int ks=x/pw[pos-i]%10; f[i][10][10][0][0][0][0]=1;// 刷表for(int j=0;j<=10;j++){for(int k=0;k<=10;k++){for(int l=0;l<=1;l++){for(int p=0;p<=1;p++){// 這位for(int q=0;q<=9;q++){if(j==10&&k==10&q==0)continue;bool b1=0,c1=0,d1=0;if(j==k&&j==q)b1=1;if(q==4)c1=1;if(q==8)d1=1;f[i][k][q][l|c1][p|d1][1][0]+=f[i-1][j][k][l][p][1][0];f[i][k][q][l|c1][p|d1][b1][0]+=f[i-1][j][k][l][p][0][0];}for(int q=0;q<=ks;q++){if(j==10&&k==10&q==0)continue;bool b1=0,c1=0,d1=0;if(j==k&&j==q)b1=1;if(q==4)c1=1;if(q==8)d1=1;if(q!=ks){f[i][k][q][l|c1][p|d1][1][0]+=f[i-1][j][k][l][p][1][1];f[i][k][q][l|c1][p|d1][b1][0]+=f[i-1][j][k][l][p][0][1];}else {f[i][k][q][l|c1][p|d1][1][1]+=f[i-1][j][k][l][p][1][1];f[i][k][q][l|c1][p|d1][b1][1]+=f[i-1][j][k][l][p][0][1];}}}}}}}ll ans=0;for(int i=0;i<=9;i++)for(int j=0;j<=9;j++)for(int k=0;k<=1;k++)for(int l=0;l<=1;l++)for(int s=0;s<=1;s++){if(k&&l)continue;ans+=f[pos][i][j][k][l][1][s];}return ans;}ll l,r;int main(){scanf("%lld%lld",&l,&r);printf("%lld\n",solve(r)-solve(l-1));return 0;}
bzoj 4521: [Cqoi2016]手機號碼