bzoj 4521 [ Cqoi 2016 ] 手机号码 —— 数位DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4521
数位DP,记录好多维状态;
写了半天,复杂得写不下去了,于是参考一下TJ...
练习简洁地写出数位DP。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; ll l,r,f[15][15][3][3][3][3],a[15],ans;//i,数字,限制,二连,三连, 4/8 int tmp[15]; ll solve(ll mx) { ll tt=mx; for(int i=1;i<=11;i++)a[i]=tt%10,tt/=10; memset(f,0,sizeof f); f[12][0][1][0][0][0]=1;//1 表示有限制 for(int i=11;i;i--) for(int j=0;j<=9;j++)//i+1 for(int t1=0;t1<=1;t1++)//限制 for(int t2=0;t2<=1;t2++)//二连 for(int t3=0;t3<=1;t3++)//三连 for(int t4=0;t4<=2;t4++)// 4/8 if(f[i+1][j][t1][t2][t3][t4]) { for(int k=0;k<=(t1?a[i]:9);k++) { if((t4==1&&k==8)||(t4==2&&k==4))continue; f[i][k][t1&&k==a[i]][k==j][t3|(t2&&k==j)][t4|tmp[k]]+= f[i+1][j][t1][t2][t3][t4]; } } ll ans=0; for(int j=0;j<=9;j++) for(int t1=0;t1<=1;t1++) for(int t2=0;t2<=1;t2++) for(int t4=0;t4<=2;t4++) ans+=f[1][j][t1][t2][1][t4]; return ans; } int main() { scanf("%lld%lld",&l,&r); tmp[4]=1; tmp[8]=2; printf("%lld\n",solve(r)-solve(l-1)); return 0; }