HDU 4352
Posted tiberius
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4352相关的知识,希望对你有一定的参考价值。
题意略。
思路:
这一发A得实在是难能可贵。因此我要记录一下。
首先这个题很明显是个数位dp,其难点在于如何知道填到当前这一位时,我的最长上升子序列是多长。
如果是一个简单的求最长上升子序列的题,我们一般会在一个数组中使用二分法,每次查找新来的这个数字在这个数组中应该排什么位置。
但是我们记录状态不可能还带着一个数组。回过头来仔细研究一下这种数组的性质,你会发现它数组内的元素一定是从前到后严格递增的。
那其实我们可以只记录在当前状态时,这个数组中都有哪些元素就可以了,因为反正是两两不同且严格递增的。
又考虑到这个数组中只可能存在0~9这10个数,因此我们可以状态压缩一下。
从这个角度来说,本题同时考察了状压dp和数位dp。
1.要设置前导0,在无前导0的情况下,0可以计入状态集合;在有前导0的情况下,0不可以计入。因为09这种上升序列不合题意。
2.dp[pos][state][k] 表示 考虑到pos位,排序数组中的状况是state,最长上升子序列长度为k。
代码附上:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn0 = 20; 5 const int maxn1 = (1<<10) + 5; 6 const int maxn2 = 15; 7 8 LL dp[maxn0][maxn1][maxn2],l,r; 9 int a[maxn0],store[maxn0],k,t,tail,T; 10 11 int cnt1(int x) 12 int ret = 0; 13 while(x) 14 x = x & (x - 1); 15 ret += 1; 16 17 return ret; 18 19 void process(LL x) 20 tail = 0; 21 while(x) 22 a[tail++] = int(x % 10); 23 x /= 10; 24 25 26 inline void decode(int x) 27 t = 0; 28 for(int i = 0;(x>>i) > 0;++i) 29 int temp = (x>>i); 30 if(temp & 1) store[t++] = i; 31 32 store[t] = maxn0; 33 34 inline int encode() 35 int ret = 0; 36 for(int i = 0;i < t;++i) ret += (1<<store[i]); 37 return ret; 38 39 LL dfs(int pos,int state,bool limit,bool lead,int kk) 40 41 if(pos == -1) return cnt1(state) == k ? 1 : 0; 42 if(!limit && !lead && dp[pos][state][kk] != -1) return dp[pos][state][kk]; 43 44 int up = limit ? a[pos] : 9; 45 LL ret = 0; 46 for(int i = 0;i <= up;++i) 47 decode(state); 48 int idx = lower_bound(store,store + t,i) - store; 49 if(idx + 1 > k) break; 50 51 store[idx] = i; 52 t = max(idx + 1,t); 53 54 int nstate = (i == 0 && lead) ? state : encode(); 55 ret += dfs(pos - 1,nstate,limit && i == up,lead && i == 0,kk); 56 57 if(!limit && !lead) dp[pos][state][kk] = ret; 58 return ret; 59 60 61 int main() 62 63 scanf("%d",&T); 64 memset(dp,-1,sizeof(dp)); 65 int cas = 1; 66 while(T--) 67 scanf("%lld%lld%d",&l,&r,&k); 68 69 process(l - 1); 70 LL ans0 = dfs(tail - 1,0,true,true,k); 71 72 process(r); 73 LL ans1 = dfs(tail - 1,0,true,true,k); 74 75 printf("Case #%d: %lld\n",cas++,ans1 - ans0); 76 77 return 0; 78
以上是关于HDU 4352的主要内容,如果未能解决你的问题,请参考以下文章