很久以前就。。。但是一直咕咕咕
思路:数位$DP$
提交:1次
题解:见代码
#include<cstdio> #include<iostream> #include<cstring> #define ll long long #define R register ll using namespace std; ll f[15][15],a,b; //f[l][sum]对应dfs中(因为只在!ul&&!ck的时候记忆化) int num[15]; ll dfs(int l,bool ul,bool ck,int lst,int sum) {//l剩余位数,ul上界标记,ck前导零标记,lst为所统计的数,sum是统计出现了几次合法的数字 if(!l) return sum; if(!ul&&!ck&&~f[l][sum]) return f[l][sum];//记忆化 R mx=(ul?num[l]:9),cnt=0;//判断上界 for(R i=0;i<=mx;++i) cnt+=dfs(l-1,ul&&(i==mx),ck&&!i,lst,sum+((!ck||i)&&(i==lst)));//sum++,当且仅当不是一直是前导零或有数,同时是所统计的数 return ul||ck?cnt:f[l][sum]=cnt;//记忆化 } inline ll solve(ll x,int n) { R len=0; memset(f,0xff,sizeof(f)); for(;x;x/=10) num[++len]=x%10;//按位分解 return dfs(len,true,true,n,0); } signed main() { scanf("%lld%lld",&a,&b); for(R i=0;i<=9;++i) printf("%lld ",solve(b,i)-solve(a-1,i));//前缀和 putchar('\n'); } #include<cstdio> #include<iostream> #include<cstring> #define R register int using namespace std; int a,b,f[12][10],num[11]; //f[i][j]搜到第i位,前一位是j,且没有上界标记的方案数 inline int max(int a,int b){return a>b?a:b;} inline int abs(int x){return x>0?x:-x;} int dfs(int l,bool ul,bool ck,int lst) {//l位数,ul上界标记,ck前导零标记,lst上一位 if(!l) return 1; if(!ul&&(~f[l][lst])) return f[l][lst];//记忆化 R mx=ul?num[l]:9,cnt=0;//mx是上界 for(R i=0;i<=mx;++i) { if(abs(lst-i)<2) continue;//差小于2 if(ck&&i==0) cnt+=dfs(l-1,ul&&i==mx,true,-2);//若一直是前导零 else cnt+=dfs(l-1,ul&&i==mx,false,i); } return ul||ck?cnt:f[l][lst]=cnt; } inline int solve(int x) { R len=0; memset(f,0xff,sizeof(f)); for(;x;x/=10) num[++len]=x%10; return dfs(len,true,true,-2); } signed main() { scanf("%d%d",&a,&b); printf("%d\n",solve(b)-solve(a-1));//前缀和减一下 }
2019.07.18