$solution:$
首先我们可以发现一个结论,对于一个数 $x$ ,它的最低修改次数为它每位与前去中是否都比此位上的数大,有则答案 $-1$ 。因为若有小数则没有办法将其答案贡献变低。
这个东西可以直接单调栈维护一个递增序列。
所以这样 $dp$ 状态也很显然了,设 $f_{i,j,sta}$ 表示当前到 $i$ 位,答案为 $j$ ,$sta$ 表示当前栈中 $0-9$ 是否在栈中。
简单数位转移即可。
时间复杂度 $O(10 imes 18^2 imes 2^{10})$ 。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define int long long inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=21; int dig[11],f[MAXN][MAXN][1<<10]; int l,r,k,cnt; void debug(int sta){ int Dig[10]; Dig[0]=0; while(sta){ Dig[++Dig[0]]=sta%2; sta/=2; } for(int i=Dig[0];i>=1;i--) printf("%d ",Dig[i]);printf(" "); return ; } int dfs(int ps,int K,int sta,int done){ if(!done&&f[ps][K][sta]!=-1) return f[ps][K][sta]; if(ps==0){ if(K==k) return 1; return 0; } int end,Ans=0; if(done) end=dig[ps]; else end=9; for(int i=0;i<=end;i++){ int S=sta; for(int j=i+1;j<=9;j++) if(S&(1<<j)) S-=(1<<j); if(S&(1<<i)) Ans+=dfs(ps-1,K,S,done&(i==dig[ps])); else Ans+=dfs(ps-1,K+1,S+(1<<i),done&(i==dig[ps])); } if(done==0) f[ps][K][sta]=Ans; return Ans; } int solve(int x){ dig[0]=0; while(x){ dig[++dig[0]]=x%10; x/=10; } return dfs(dig[0],0,1,1); } signed main(){ freopen("digit.in","r",stdin); freopen("digit.out","w",stdout); memset(f,-1,sizeof(f)); l=read(),r=read(),k=read(); printf("%lld ",solve(r)-solve(l-1));return 0; }