题意略。

思路:

这一发A得实在是难能可贵。因此我要记录一下。

首先这个题很明显是个数位dp,其难点在于如何知道填到当前这一位时,我的最长上升子序列是多长。

如果是一个简单的求最长上升子序列的题,我们一般会在一个数组中使用二分法,每次查找新来的这个数字在这个数组中应该排什么位置。

但是我们记录状态不可能还带着一个数组。回过头来仔细研究一下这种数组的性质,你会发现它数组内的元素一定是从前到后严格递增的。

那其实我们可以只记录在当前状态时,这个数组中都有哪些元素就可以了,因为反正是两两不同且严格递增的。

又考虑到这个数组中只可能存在0~9这10个数,因此我们可以状态压缩一下。

从这个角度来说,本题同时考察了状压dp和数位dp。

1.要设置前导0,在无前导0的情况下,0可以计入状态集合;在有前导0的情况下,0不可以计入。因为09这种上升序列不合题意。

2.dp[pos][state][k] 表示 考虑到pos位,排序数组中的状况是state,最长上升子序列长度为k。

 

代码附上:

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 typedef long long LL;
  4. 4 const int maxn0 = 20;
  5. 5 const int maxn1 = (1<<10) + 5;
  6. 6 const int maxn2 = 15;
  7. 7
  8. 8 LL dp[maxn0][maxn1][maxn2],l,r;
  9. 9 int a[maxn0],store[maxn0],k,t,tail,T;
  10. 10
  11. 11 int cnt1(int x){
  12. 12 int ret = 0;
  13. 13 while(x){
  14. 14 x = x & (x - 1);
  15. 15 ret += 1;
  16. 16 }
  17. 17 return ret;
  18. 18 }
  19. 19 void process(LL x){
  20. 20 tail = 0;
  21. 21 while(x){
  22. 22 a[tail++] = int(x % 10);
  23. 23 x /= 10;
  24. 24 }
  25. 25 }
  26. 26 inline void decode(int x){
  27. 27 t = 0;
  28. 28 for(int i = 0;(x>>i) > 0;++i){
  29. 29 int temp = (x>>i);
  30. 30 if(temp & 1) store[t++] = i;
  31. 31 }
  32. 32 store[t] = maxn0;
  33. 33 }
  34. 34 inline int encode(){
  35. 35 int ret = 0;
  36. 36 for(int i = 0;i < t;++i) ret += (1<<store[i]);
  37. 37 return ret;
  38. 38 }
  39. 39 LL dfs(int pos,int state,bool limit,bool lead,int kk){
  40. 40
  41. 41 if(pos == -1) return cnt1(state) == k ? 1 : 0;
  42. 42 if(!limit && !lead && dp[pos][state][kk] != -1) return dp[pos][state][kk];
  43. 43
  44. 44 int up = limit ? a[pos] : 9;
  45. 45 LL ret = 0;
  46. 46 for(int i = 0;i <= up;++i){
  47. 47 decode(state);
  48. 48 int idx = lower_bound(store,store + t,i) - store;
  49. 49 if(idx + 1 > k) break;
  50. 50
  51. 51 store[idx] = i;
  52. 52 t = max(idx + 1,t);
  53. 53
  54. 54 int nstate = (i == 0 && lead) ? state : encode();
  55. 55 ret += dfs(pos - 1,nstate,limit && i == up,lead && i == 0,kk);
  56. 56 }
  57. 57 if(!limit && !lead) dp[pos][state][kk] = ret;
  58. 58 return ret;
  59. 59 }
  60. 60
  61. 61 int main(){
  62. 62
  63. 63 scanf("%d",&T);
  64. 64 memset(dp,-1,sizeof(dp));
  65. 65 int cas = 1;
  66. 66 while(T--){
  67. 67 scanf("%lld%lld%d",&l,&r,&k);
  68. 68
  69. 69 process(l - 1);
  70. 70 LL ans0 = dfs(tail - 1,0,true,true,k);
  71. 71
  72. 72 process(r);
  73. 73 LL ans1 = dfs(tail - 1,0,true,true,k);
  74. 74
  75. 75 printf("Case #%d: %lld\n",cas++,ans1 - ans0);
  76. 76 }
  77. 77 return 0;
  78. 78 }

 

版权声明:本文为tiberius原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/tiberius/p/11439548.html