数位dp第一题
题意:找从n到m中,不包含4,62(连续)的个数
先预处理出f数组 f[i][j]是以j开头的i位数不包含4,62的个数,可通过递推求解
递推关系式为: f[i][j]=f[i-1][k]+f[i][j];对于第i位,可由第i-1位转移过来,用k枚举第i-1位的所有情况,j枚举第i位的所有情况,这时只需判断i和i-1位不为62,i位不为2的情况
用digit数组来记录从右到左的第i位,然后从最高位(最左边)开始枚举,从0枚举到digit【i】
例如432,这样便列举了所有情况
4 | 3 | 2 | 4 | 3 | 2 | 4 | 3 | 2 | |
枚举 | 0 | 枚举到3的取值 | 枚举到2的取值 | 4 | 0 | 枚举到2的取值 | 4 | 3 | 0 |
1 | 枚举到3的取值 | 枚举到2的取值 | 4 | 1 | 枚举到2的取值 | 4 | 3 | 1 | |
2 | 枚举到3的取值 | 枚举到2的取值 | 4 | 2 | 枚举到2的取值 | ||||
3 | 枚举到3的取值 | 枚举到2的取值 | |||||||
如果枚举完之后,保持最大值不变的情况下出现了4,62,则退出,如6231(枚举到3或1的情况时62会保持出现,这种情况要删去)
非递归版本的
#include<bits/stdc++.h> #define C 0.5772156649 #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const double g=10.0,eps=1e-7; const int N=10+10,maxn=1000000+10,inf=0x3f3f3f; int f[N][N];//f[i][j]以j开头的i位数不包含4,62的个数 int digit[10];//从右到左第i位是多少 int getnum(int x) { int len=0,ans=0; memset(digit,0,sizeof digit); while(x) { digit[++len]=x%10; x/=10; } for(int i=len; i>=1; i--) { for(int j=0; j<digit[i]; j++) if(j!=4&&(j!=2||digit[i+1]!=6)) ans+=f[i][j]; if(digit[i]==4||(digit[i]==2&&digit[i+1]==6))break; } return ans; } int main() { ios::sync_with_stdio(false); cin.tie(0); f[0][0]=1; for(int i=1;i<=7;i++) for(int j=0;j<=9;j++)//第i位 for(int k=0;k<=9;k++)//第i-1位 if(j!=4&&(j!=6||k!=2)) f[i][j]=f[i-1][k]+f[i][j]; int n,m; while(cin>>n>>m) { if(!n&&!m)break; cout<<getnum(m+1)-getnum(n)<<endl; } return 0; } /******************** ********************/
递归版本的
#include<bits/stdc++.h> #define C 0.5772156649 #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const double g=10.0,eps=1e-7; const int N=20+10,maxn=1000000+10,inf=0x3f3f3f; int dp[N][N],digit[N]; int dfs(int len,bool state,bool fp)//state-当前是不是等于6,fp是否访问过 { if(!len)return 1; if(!fp&&dp[len][state]!=-1)return dp[len][state]; int ret=0,fpmax=fp ? digit[len] : 9; for(int i=0;i<=fpmax;i++) { if(i==4||state&&i==2)continue; ret+=dfs(len-1,i==6,fp&&i==fpmax); } if(!fp)dp[len][state]=ret; return ret; } int solve(int x) { int len=0; while(x) { digit[++len]=x%10; x/=10; } return dfs(len,0,1); } int main() { ios::sync_with_stdio(false); cin.tie(0); int a,b; memset(dp,-1,sizeof dp); while(cin>>a>>b) { if(a==0&&b==0)break; cout<<solve(b)-solve(a-1)<<endl; } return 0; } /******************** ********************/
发现网上的代码关于数位dp的几乎都是递归写的,所以还是找递归版本理解比较好