题目链接
求区间里面的数,满足数位上的数是严格的长度为k的上升子序列的个数
上升子序列使用nlogn的计算方式,因为是严格的上升子序列,所以只会有0-9,10个数字。在某一个上升的子序列中,每个数字只会出现一次,使用f[i][s]:表示将数字i加入状态s可以到达的新的状态s’,这个f函数,可以直接暴力预处理,然后就是裸的数位dp了
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define LL long long
#define gcd __gcd
#define LCM(x,y) x/gcd(x,y)*y
#define dbg(x) printf("deg: # ::: %d\n",x);
#define cl(a,b) memset(a,b,sizeof(a))
const int maxn = 1005;
LL dp[20][1<<11][11];
int k,bit[20];
int f[11][1<<11];
int cnt(int s){
int ans = 0;
while(s){
ans+=s%2;
s/=2;
}
return ans;
}
LL dfs(int i,int s,bool e,bool z){
if(i == 0) return cnt(s) == k;
if(!e && ~dp[i][s][k]) return dp[i][s][k];
int u = e?bit[i]:9;
LL ans = 0;
for(int d=0;d<=u;d++){
ans += dfs(i-1,z&&!d?s:f[d][s],e&&u==d,z&&!d);
}
return e?ans:dp[i][s][k]=ans;
}
LL fff(LL num){
int len = 0;
while(num){
bit[++len]=num%10;
num/=10;
}
return dfs(len,0,1,1);
}
int ff(int x,int num){
for(int i=x;i<=9;i++)if(num&(1<<i)){
return num^(1<<i)|(1<<x);
}
return num|(1<<x);
}
void init(){
for(int i=0;i<=9;i++){
for(int j=0;j<(1<<10);j++){
f[i][j]=ff(i,j);
}
}
}
int main(){
int T;scanf("%d",&T);int cas = 1;
cl(dp,-1);init();
while(T--){
LL L,R;
scanf("%lld%lld%d",&L,&R,&k);
printf("Case #%d: %lld\n",cas++, fff(R)-fff(L-1));
}
return 0;
}