1781: 上升序列数
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 8 Solved: 3
[ Submit][ Status][ Web Board]
Description
假设有一个数列1,4,5,6,6,7那么这个数列的严格上升子序列就是1,4,5,6,7。现在有一个数比如123,如果单独看123的每一位就是1,2,3,
那么我们就能得到长度是3的(1,2,3)的严格上升子序列。假设一个数的最长的严格上升子序列长度是k,那么这个数就是k魅力数,现在我需
要计算区间[L,R]中有几个k魅力数?
Input
一个T(T<=10000),接下来T行,每行三个数L,R,K(0<L<=R<2^63.1<=K<=10)
Output
Case #x: y,x是测试编号从1开始,y表示答案
Sample Input
1123 321 2
Sample Output
Case #1: 139
当时校赛的时候看到这题的时候内心小小的激动了一下 因为这题在杭电(hdu4352)上看到过 不过遗憾的是这题紧紧看过因为
能力有限所以当时没有动手写 虽然校赛的时候还是不知道怎么写 不过后来看了大佬们的题解就知道了要用到nlogn
的上升子序列算法因为数字只有10个,我们可以状态压缩 因为数字只有10个所以用状态压缩
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
#define LL long long
#define cl(a,b) memset(a,b,sizeof(a))
#define MAXN 7
#define pi acos(-1)
LL dp[25][1<<10][11];//i为当前进行到的数位,j状态压缩,为10个数字出现过的,其中1的个数就是最长上升子序列,k要求的上升子序列的长度
int bit[200];
LL k;
int nloglis(int x,int s)
{
for(int i=x;i<10;i++)
if(s&(1<<i))return(s^(1<<i))|(1<<x);
return s|(1<<x);
}
int calnum(int n)
{
int l=0;
while(n)
{
if(n&1)l++;
n>>=1;
}
return l;
}
LL dfs(int pos,int num,int flag,int zero)
{
if(pos==-1)return calnum(num)==k;
if(!flag&&dp[pos][num][k]!=-1)return dp[pos][num][k];
LL ans=0;
int s=flag?bit[pos]:9;
for(int i=0;i<=s;i++)
{
int num1;
if(zero&&!i)num1=0;
else num1=nloglis(i,num);
ans+=dfs(pos-1,num1,flag&&i==s,zero&&!i);
}
if(!flag)dp[pos][num][k]=ans;
return ans;
}
LL solve(LL n)
{
int l=0;
while(n)
{
bit[l++]=n%10;
n/=10;
}
return dfs(l-1,0,1,1);
}
int main()
{
int t,test=0;
LL l,r;
cl(dp,-1);
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&l,&r,&k);
printf("Case #%d: %lld\n",++test,solve(r)-solve(l-1));
}
return 0;
}