这个题最不好想到的是状态的保存,也没有几亿的数组让你开,怎么保存前面出现了哪些数字。
题意让你求最长上升子序列的长度为k的数字的数目,可以是不连续的,可以保留一个状态栈,栈顶部依次更新,再保证长度最大的情况下使栈顶元素最小,这样就能保证下次加进来的元素有可能会使长度增加。这个状态就用2进制来表示,1的个数就是最后的长度。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
using namespace std;
#define N 100000
#define LL long long
#define INF 0xfffffff
const double eps = 1e-;
const double pi = acos(-1.0);
const double inf = ~0u>>;
LL dp[][<<][];
int dd[],k,d[];
LL dfs(int i,int e,int tt)
{
if(i==-)
{
int num = ;
for(int g = ;g <= ;g++)
if((<<g)&tt)
num++;
return num==k;
}
if(!e&&dp[i][tt][k]!=-) return dp[i][tt][k];
int mk = e?d[i]:;
LL ans = ;
int j;
for(j=;j <= mk ; j++)
{
int te = tt;
for(int g = j; g <= ; g++)
{
if((<<g)&tt)
{
te-=(<<g);
break;
}
}
if(tt||j!=)
te|=(<<j);
ans+=dfs(i-,e&&j==mk,te);
}
return e?ans:dp[i][tt][k] = ans;
}
LL cal(LL x)
{
int dd[];
memset(dd,,sizeof(dd));
int g = ;
while(x)
{
d[g++] = x%;
x/=;
}
return dfs(g-,,);
}
int main()
{
int t;
LL l,r;
cin>>t;
memset(dp,-,sizeof(dp));
int kk = ;
while(t--)
{
cin>>l>>r>>k;
printf("Case #%d: ",++kk);
cout<<cal(r)-cal(l-)<<endl;
}
return ;
}