LOJ#2044. 「CQOI2016」手机号码 数位dp
作者:互联网
这次的状态十分复杂,写递推版不现实.
于是学了一下递归版数位dp,感觉比递推版高明多了,好写还好想.
如果以后碰到状态复杂的数位dp的话可以考虑递归版本.
code:
#include <bits/stdc++.h> #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int num[20],cnt; ll dp[20][20][20][2][2][2][2],L,R; // dp[当前位置][前一个位置的数][前 2 个位置的数][是否合法][有 4][有 8][是否顶上界] ll calc(int pos,int a,int b,bool state,bool f,bool e,bool li) { if(f&&e) return 0; if(!pos) return state; if(!li&&dp[pos][a][b][state][f][e][li]!=-1) return dp[pos][a][b][state][f][e][li]; ll det=0; int m=li?num[pos]:9; for(int i=0;i<=m;++i) det+=calc(pos-1,i,a,state||(i==a&&i==b),f||(i==4),e||(i==8),li&&(i==m)); if(!li) dp[pos][a][b][state][f][e][li]=det; return det; } ll sol(ll x) { cnt=0,memset(num,0,sizeof(num)); do { num[++cnt]=x%10; x/=10; }while(x); if(cnt!=11) return 0; ll ans=0; memset(dp,-1,sizeof(dp)); for(int i=1;i<=num[cnt];++i) ans+=calc(cnt-1,i,0,0,i==4,i==8,i==num[cnt]); return ans; } int main() { // setIO("input"); scanf("%lld%lld",&L,&R); printf("%lld\n",sol(R)-sol(L-1)); return 0; }
标签:2044,20,LOJ,ll,pos,li,int,CQOI2016,dp 来源: https://www.cnblogs.com/guangheli/p/13098134.html