题目大意:求给定区间呢的数满足最长子序列长度为k;
题目解析:LIS,dp第二维表示当前的序列,第三维表示目标长度为k,dfs的时候更新序列的时候要像LIS一样找到>=i的第一位并且去掉然后加上第i位;
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
ll dp[20][1<<10][20],num[20];
int getbit(int x)
{
int ans=0;
while(x)
{
if(x&1) ans++;
x>>=1;
}
return ans;
}
int k;
int update(int x,int s)
{
for(int i=x;i<=9;i++)
{
if(s&(1<<i))
{
return (s^(1<<i))|(1<<x);
}
}
return s|(1<<x);
}
ll dfs(int pos,int s,bool lead,bool limit)
{
if(pos==-1) return getbit(s)==k;
if(!lead&&!limit&&dp[pos][s][k]!=-1) return dp[pos][s][k];
int u=limit?num[pos]:9;
ll ans=0;
for(int i=0;i<=u;i++)
{
if(lead&&i==0)
ans+=dfs(pos-1,0,true,limit&&i==u);
else
ans+=dfs(pos-1,update(i,s),lead&&(i==0),limit&&(i==u));
}
if(!lead&&!limit) return dp[pos][s][k]=ans;
return ans;
}
ll solve(ll n)
{
int cnt=0;
while(n)
{
num[cnt++]=n%10;
n/=10;
}
return dfs(cnt-1,0,true,true);
}
int main()
{
int cas,c=1;
memset(dp,-1,sizeof(dp));
scanf("%d",&cas);
while(cas--)
{
ll a,b;
scanf("%lld%lld%d",&a,&b,&k);
printf("Case #%d: ",c++);
printf("%lld\n",solve(b)-solve(a-1));
}
return 0;
}