hdu4352 XHXJ's LIS

本文介绍了如何通过状态保存和2进制表示来解决求最长上升子序列长度为k的数字数目问题。使用深度优先搜索算法,通过维护一个状态栈来跟踪已出现的数字,确保在保持最大长度的同时使栈顶元素尽可能小。

链接

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

题意让你求最长上升子序列的长度为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

 

转载于:https://www.cnblogs.com/shangyu/p/3682991.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值