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

 

你可能感兴趣的:(HDU)