码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 4352 XHXJ's LIS

时间:2018-09-27 22:15:00      阅读:196      评论:0      收藏:0      [点我收藏+]

标签:stdin   long   cal   去掉   line   stdout   getc   ems   lan   

XHXJ‘s LIS

http://acm.hdu.edu.cn/showproblem.php?pid=4352

题意:

  询问L~R之间多少个数满足以下条件:将数字的每一位上的数字写成一个序列(这个序列每个数不超过10,长度不超过20),然后这个序列的最长上升子序列的长度为k。

分析:

  数位dp。

  这个状态有点特殊。首先考虑nlogn求最长上升子序列的过程,记录每长度为k上升子序列中结尾的最小的是谁。那么可以记录这个数组,每次转移更新数组即可。但是直接记录是空间开不下。但是发现这个题有一个性质:最大长度为10,最大的数字为10,而且是上升的。如果记入一个长度为10的01串。第b位上的,是从头开始第a个1,表示长度为a的最长上升子序列的结尾最小的数是b。由于是上升的,每个位上只有一个1,而且长度为10,刚好开得下。

  加入一个数后,找到第一个比它大的数,然后去掉这个,加上新加的。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #define fi(s) freopen(s,"r",stdin);
12 #define fo(s) freopen(s,"w",stdout);
13 using namespace std;
14 typedef long long LL;
15 
16 inline LL read() {
17     LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==-)f=-1;
18     for(;isdigit(ch);ch=getchar())x=x*10+ch-0;return x*f;
19 }
20 
21 int a[22], tot, k;
22 LL dp[22][(1 << 10) + 5][11];
23 
24 int getnxt(int i,int s) {
25     for (int j=i; j<=9; ++j) 
26         if ((1 << j) & s) { s ^= (1 << j); break; }
27     return s | (1 << i); // !!!
28 }
29 int getbit(int x) {
30     int res = 0;
31     while (x) res += (x & 1), x >>= 1;
32     return res;
33 }
34 LL dfs(int x,int sta,bool lim,bool fir) {
35     if (!x) return getbit(sta) == k;
36     if (!lim && dp[x][sta][k] != -1)  return dp[x][sta][k];
37     LL res = 0;
38     int u = lim ? a[x] : 9;
39     for (int i=0; i<=u; ++i) 
40         res += dfs(x - 1, fir&&i==0 ? 0 : getnxt(i, sta), lim&&i==a[x], fir&&i==0);
41     if (!lim) dp[x][sta][k] = res;
42     return res;
43 }
44 LL Calc(LL x) {
45     tot = 0;
46     while (x) {
47         a[++tot] = x % 10;
48         x /= 10;
49     }
50     return dfs(tot, 0, 1, 1);
51 }
52 int main() {
53     memset(dp, -1, sizeof(dp));
54     int T = read();
55     for (int t=1; t<=T; ++t) {
56         LL L = read(), R = read(); k = read();
57         printf("Case #%d: ",t);
58         printf("%lld\n", Calc(R) - Calc(L - 1));
59     }
60     return 0;
61 }

 

HDU 4352 XHXJ's LIS

标签:stdin   long   cal   去掉   line   stdout   getc   ems   lan   

原文地址:https://www.cnblogs.com/mjtcn/p/9715469.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!