hdu_4352_XHXJ's LIS 数位DP/状态压缩
给你一个LL范围内的区间,问你在这个区间内最长递增子序列长度恰为K的数有多少个
/* * HDU 4352 XHXJ's LIS * 问L到R,各位数字组成的严格上升子序列的长度为K的个数。 * 0<L<=R<263-1 and 1<=K<=10 * 注意这里最长上升子序列的定义,和LIS是一样的,不要求是连续的 * 所以用十位二进制表示0~9出现的情况,和O(nlogn)求LIS一样的方法进行更新 * */ #include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> using namespace std; long long dp[25][1<<10][11]; /* * dp[i][j][k]:i为当前进行到的数位,j状态压缩,为10个数字出现过的,其中1的个数就是最长上升子序列,k要求的上升子序列的长度 */ int K; int getnews(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 getnum(int s)//得到状态s中1的个数 { int ret=0; while(s) { if(s&1)ret++; s>>=1; } return ret; } int bit[25]; long long dfs(int pos,int s,bool e,bool z)//e是是不是上界标记,z是是不是前面的为0标记 { if(pos==-1)return getnum(s)==K; if(!e &&dp[pos][s][K]!=-1)return dp[pos][s][K]; long long ans=0; int end=e?bit[pos]:9; for(int i=0;i<=end;i++) ans+=dfs(pos-1,(z&&i==0)?0:getnews(i,s),e&&i==end,z&&(i==0)); if(!e)dp[pos][s][K]=ans; return ans; } long long calc(long long n) { int len=0; while(n) { bit[len++]=n%10; n/=10; } return dfs(len-1,0,1,1); } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int T; long long l,r; memset(dp,-1,sizeof(dp)); scanf("%d",&T); int iCase=0; while(T--) { iCase++; scanf("%I64d%I64d%d",&l,&r,&K); printf("Case #%d: ",iCase); printf("%I64d\n",calc(r)-calc(l-1)); } return 0; }