hdu4352 XHXJ's LIS

链接

这个题最不好想到的是状态的保存,也没有几亿的数组让你开,怎么保存前面出现了哪些数字。

题意让你求最长上升子序列的长度为k的数字的数目,可以是不连续的,可以保留一个状态栈,栈顶部依次更新,再保证长度最大的情况下使栈顶元素最小,这样就能保证下次加进来的元素有可能会使长度增加。这个状态就用2进制来表示,1的个数就是最后的长度。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 100000
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 LL dp[22][1<<10][11];
18 int dd[22],k,d[22];
19 LL dfs(int i,int e,int tt)
20 {
21     if(i==-1)
22     {
23         int num = 0;
24         for(int g = 0 ;g <= 9 ;g++)
25         if((1<<g)&tt)
26         num++;
27         return num==k;
28     }
29     if(!e&&dp[i][tt][k]!=-1) return dp[i][tt][k];
30     int mk = e?d[i]:9;
31     LL ans = 0;
32     int j;
33     for(j=0;j <= mk ; j++)
34     {
35         int te = tt;
36         for(int g = j; g <= 9 ; g++)
37         {
38             if((1<<g)&tt)
39             {
40                 te-=(1<<g);
41                 break;
42             }
43         }
44         if(tt||j!=0)
45         te|=(1<<j);
46         ans+=dfs(i-1,e&&j==mk,te);
47     }
48     return e?ans:dp[i][tt][k] = ans;
49 }
50 LL cal(LL x)
51 {
52     int dd[11];
53     memset(dd,0,sizeof(dd));
54     int g = 0;
55     while(x)
56     {
57         d[g++] = x%10;
58         x/=10;
59     }
60     return dfs(g-1,1,0);
61 }
62 int main()
63 {
64     int t;
65     LL l,r;
66     cin>>t;
67     memset(dp,-1,sizeof(dp));
68     int kk =0 ;
69     while(t--)
70     {
71         cin>>l>>r>>k;
72         printf("Case #%d: ",++kk);
73         cout<<cal(r)-cal(l-1)<<endl;
74     }
75     return 0;
76 }
View Code

 

posted @ 2014-04-23 15:18  _雨  阅读(269)  评论(0编辑  收藏  举报