【题意】
问区间[L, R]里面满足 LIS == k的数字个数。
【解题方法】
LIS运用动态规划可以在nlogn的时间复杂度解决,此略。 因为最多只有0-9十个数字,因此可以预处理。 .sta为LIS
的状态,siz[sta]中保存LIS
的长度(即二进制中1的个数),nex[sta][i]为在sta中插入 数字i之后的
状态。 dp[l][sta][k] l为数字长度,sta为当前
的状态,k为所要求的LIS
长度。 dfs(int l,int sta,bool zero,bool jud) :zero判断是否为前导零,jud为是否为边 界。 注意:dp[l][sta][k]中,k并不是必须的,然而因为本题样例组数过多且k很小,所以选择增加 一维表状态而不是每次都初始化以节约时间。
【AC 代码】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
inline LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int digit[20],siz[1<<10],nex[1<<10][10];
LL dp[66][(1<<10)][11];
int k;
LL dfs(int l,int sta,bool zero,bool jud){
if(l==0) return siz[sta]==k;
if(!jud&&dp[l][sta][k]!=-1) return dp[l][sta][k];
int nes=jud?digit[l]:9;
LL ans=0;
for(int i=0; i<=nes; i++){
ans+=dfs(l-1,(zero&&i==0)?0:nex[sta][i],zero&&i==0,jud&&i==nes);
}
if(!jud) dp[l][sta][k]=ans;
return ans;
}
LL f(LL num){
int pos=0;
while(num){
digit[++pos]=num%10;
num/=10;
}
return dfs(pos,0,true,true);
}
int find_nex(int status,int num){
for(int i=num; i<10; i++){
if(status&(1<<i)) return (status^(1<<i)|(1<<num));
}
return status|(1<<num);
}
int main()
{
LL n,m;
int T,cas=1;
memset(dp,-1,sizeof(dp));
for(int i=0; i<(1<<10); i++){
siz[i]=0;
for(int j=0; j<10; j++){
if(i&(1<<j)) siz[i]++;
nex[i][j]=find_nex(i,j);
}
}
scanf("%d",&T);
while(T--){
m=read(),n=read(),k=read();
LL ans=f(n)-f(m-1);
printf("Case #%d: %I64d\n",cas++,ans);
}
}