CF 1073 E. Segment Sum
https://codeforces.com/problemset/problem/1073/E
题意:[l,r]中,出现0—9数字的种类数不超过k的数的和
dp[i][j][0/1] 表示 dfs到第i位以后,数字出现的情况状态为j能转移的状态,是否有上界限制的数字的和
f[i][j] 表示 dfs到第i位以后,数字出现的情况状态为j能转移的状态,没有上界限制的数字的个数
枚举这一位填什么
加上这一位的贡献,加上填上这一位之后后面数的贡献
数字出现状态:若i出现过,则状态j的第i位二进制位为1
#include<cstdio> #include<cstring> using namespace std; typedef long long LL; const int mod=998244353; int dp[20][(1<<10)+2][2],f[20][(1<<10)+2]; int ans,m; int a[20],pow10[20]; bool va[(1<<10)+2]; int k; LL dfs(int dep,int s,int lim,bool zero) { if(!va[s]) return 0; if(!lim && f[dep][s]!=-1) return f[dep][s]; if(!dep) return 1; int up=lim ? a[dep] : 9,nl,news,tmp; int sum=0; for(int i=0;i<=up;++i) { if(zero && !i) news=0; else news=s|1<<i; nl=lim && a[dep]==i; tmp=dfs(dep-1,news,nl,zero && !i); dp[dep][s][lim]+=1ll*tmp*i%mod*pow10[dep-1]%mod; dp[dep][s][lim]%=mod; dp[dep][s][lim]+=dp[dep-1][news][nl]; dp[dep][s][lim]%=mod; sum+=tmp; sum%=mod; } if(!lim) f[dep][s]=sum; return sum; } void solve(long long n,int ty) { int len=0; while(n) a[++len]=n%10,n/=10; memset(f,-1,sizeof(f)); memset(dp,0,sizeof(dp)); dfs(len,0,1,1); ans+=ty*dp[len][0][1]; ans%=mod; if(ans<0) ans+=mod; } bool check(int s) { int p=0; for(int i=0;i<=9;++i) if(s&1<<i) p++; if(p<=k) return 1; else return 0; } int main() { LL l,r; scanf("%lld%lld%d",&l,&r,&k); pow10[0]=1; for(int i=1;i<19;++i) pow10[i]=1ll*pow10[i-1]*10%mod; m=1<<10; for(int i=0;i<m;++i) va[i]=check(i); solve(r,1); solve(l-1,-1); printf("%d",ans); }