题意:
给x、y、k,在[x,y] 范围内最长上升子序列长度是k的数有几个
思路:
模仿 LIS nlogn的想法,这里就只有10个数,进行状压
然后直接搜就好了不用二分
然后按位dp下去就ok了!
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
//2014年9月26日09:46:04
__int64 dp[22][1024][11];
int num[22];
struct node
{
int n,l;
};
node js(int n,int x,int tep)
{
node ans;
ans.l=tep;
int i;
for(i=x; i<10; i++) if(n&(1<<i)) break;
if(i==10) //没找到 长度加一 填上那个数
{
ans.l=tep+1;
n|=(1<<x);
}
else //找到 更新那个数
{
n^=(1<<i);
n|=(1<<x);
}
ans.n=n;
return ans;
}
__int64 dfs(int site,int n,int l,int k,int zero,int f)
{
if(site==0)
{
if(zero) return 0;
return l==k;
}
if(!f&&!zero&&~dp[site][n][k]) return dp[site][n][k];
int len=f?num[site]:9;
__int64 ans=0;
for(int i=0; i<=len; i++)
{
node tep;
if(zero)
{
if(i==0) ans+=dfs(site-1,n,l,k,zero&&i==0,f&&i==len);
else
{
tep=js(n,i,l);
ans+=dfs(site-1,tep.n,tep.l,k,zero&&i==0,f&&i==len);
}
}
else
{
tep=js(n,i,l);
ans+=dfs(site-1,tep.n,tep.l,k,zero&&i==0,f&&i==len);
}
}
if(!f&&!zero) dp[site][n][k]=ans;
return ans;
}
__int64 solve(__int64 x,int k)
{
int cnt=0;
while(x)
{
num[++cnt]=x%10;
x/=10;
}
return dfs(cnt,0,0,k,1,1);
}
int main()
{
int t,cas=1;
cin>>t;
memset(dp,-1,sizeof(dp));
while(t--)
{
__int64 x,y;
int k;
scanf("%I64d%I64d%d",&x,&y,&k);
printf("Case #%d: %I64d
",cas++,solve(y,k)-solve(x-1,k));
}
return 0;
}
//2014年9月26日10:24:07