hdu4352_状压+数位+lis

题目链接

原文:http://www.acmerblog.com/hdu-4352-xhxjs-lis-7363.html

 * 问L到R,各位数字组成的严格上升子序列的长度为K的个数。
 * 0<L<=R<263-1 and 1<=K<=10
 * 注意这里最长上升子序列的定义,和LIS是一样的,不要求是连续的
 * 所以用十位二进制表示0~9出现的情况,和O(nlogn)求LIS一样的方法进行更新

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <vector>
 7 #include <ctime>
 8 #include <queue>
 9 #include <list>
10 #include <set>
11 #include <map>
12 using namespace std;
13 #define INF 0x3f3f3f3f
14 typedef long long LL;
15
16 int bit[35];
17 LL dp[35][15][1 << 10], k;
18
19 int GetNext(int st,int x)
20 {  //刚开始用数组存,会超时啊(大哭),还是太嫩了
21     //找到第一个大于x的数并且替换他,nlogn求最长递增子序列的思想
22     for(int i=x;i<10;i++)
23         if(st&(1<<i)) return ((st^(1<<i))|(1<<x));
24     return st|(1<<x);
25 }
26 int GetLen(int st)
27 {
28     int cnt=0;
29     while(st)
30     {
31         if(st&1) cnt++;
32         st>>=1;
33     }
34     return cnt;
35 }
36 LL dfs(int len, int length, int mark, int flag)
37 {//刚开始一直用dp[len][length][mark], 跟length没有毛线关系啊,wa了n发
38     if(len == 0)
39         return GetLen(mark) == k;
40     if(flag && dp[len][k][mark] >= 0)
41         return dp[len][k][mark];
42     LL sum = 0;
43     int te = flag ? 9 : bit[len];
44     for(int i = 0; i <= te; i++)
45     {
46         int Mark = ((length==0 && i==0) ? 0 : GetNext(mark, i));
47         sum += dfs(len - 1, length || i , Mark, flag || (i < te));
48     }
49     if(flag)
50         dp[len][k][mark] = sum;
51     return sum;
52 }
53 LL solve(LL n)
54 {
55     int len = 0;
56     while(n)
57     {
58         bit[++len] = n % 10;
59         n /= 10;
60     }
61     return dfs(len, 0, 0, 0);
62 }
63 int main()
64 {
65     int t;
66     LL l, r;
67     scanf("%d", &t);
68     memset(dp, -1, sizeof(dp));
69     for(int i = 1; i <= t; i++)
70     {
71         cin >> l >> r >> k;
72         cout << "Case #"<< i << ": ";
73         cout << solve(r) - solve(l - 1) << endl;
74     }
75     return 0;
76 }

时间: 2024-12-17 22:43:29

hdu4352_状压+数位+lis的相关文章

SPOJ BALNUM Balanced Numbers 状压+数位DP

一开始想了一个用二进制状压的方法,发现空间需要的太大,光光memset都要超时 = = 其实不用每次都memset 也可以用三进制,一开始直接打表出所有的状态转移就好 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream&g

lightoj-1021 - Painful Bases(状压+数位dp)

1021 - Painful Bases PDF (English) Statistics ForumTime Limit: 2 second(s) Memory Limit: 32 MBAs you know that sometimes base conversion is a painful task. But still there are interesting facts in bases. For convenience let's assume that we are deali

Topcoder SRM655 DIV2 950 NineEasy 状压 + 数位 dp

题意:要你构造一个n位的数子 ,给你m(1-5)个询问,每一次询问取一些位数的数组成一个新数且这个数 %9 ==  0 , 问你要满足这m个询问的数字有多少个(允许前缀0). 解题思路:把每一种情况状压,得到一个最多  9x9x9x9x9 的情况,然后根据 每个数的询问决定状态转移方程. 解题代码: 1 // BEGIN CUT HERE 2 /* 3 4 */ 5 // END CUT HERE 6 #line 7 "NineEasy.cpp" 7 #include <cstd

HDU 4352 XHXJ&#39;s LIS 数位DP + 状压

由LIS的nlogn解法 可以得出最后统计数组中数的个数即为LIS的长度 这样就可以状压了 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <c

HDU 4352 XHXJ&#39;s LIS (数位DP,状压)

题意: 前面3/4的英文都是废话.将一个正整数看成字符串,给定一个k,问区间[L,R]中严格的LIS=k的数有多少个? 思路: 实在没有想到字符0~9最多才10种,况且也符合O(nlogn)求LIS的特点,所以用状态压缩可以解决. 看到状态压缩的字眼基本就会做了,增加一维来保存当前LIS的状态.由于求LIS时的辅助数组d[i]表示长度为i的LIS最后一个元素,d数组是严格递增的,所以好好利用d数组的特性来设计状态压缩才是关键.压缩的状态0101可以表示:仅有0和2在数组d中,即d[1]=0,d[

HDU.4352.XHXJ&#39;s LIS(数位DP 状压 LIS)

题目链接 数位DP. 至于怎么求LIS,因为只有10个数,所以可以参照O(nlogn)求LIS的方法,状压记录状态. 每次加一个数和求LIS一样更新状态.最后状态中1的个数就是LIS的长度. //93MS 3004K #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define gc() getchar() typedef long long LL; c

CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高位数字不为0. 因此,符合我们定义的最小的有趣的数是2013.除此以外,4位的有趣的数还有两个:2031和2301. 请计算恰好有n位的有趣的数的个数.由于答案可能非常大,只需要输出答案除以1000000007的余数. 输入格式 输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000). 输

HDOJ 4906 Our happy ending 状压DP(数位DP?)

http://acm.hdu.edu.cn/showproblem.php?pid=4906 题意: N个数的序列,每个数可以选择填0-L,如果一个序列可以选出某些数,他们的和为K,那么这个序列就是”好序列“,给定N<=20,K<=20,0<=L<=10^9,问好序列的个数. 分析: N和K很小,所以要想办法利用这个特性(状压?搜索?).虽然L很大,但实际上一个数大于K的时候,肯定是不能选他组成K的.我们就先考虑L<=K的做法. 然后还是考虑不出来.. 好吧,看题解吧.. 目

SPOJ10606 BALNUM - Balanced Numbers(数位DP+状压)

Balanced numbers have been used by mathematicians for centuries. A positive integer is considered a balanced number if: 1)      Every even digit appears an odd number of times in its decimal representation 2)      Every odd digit appears an even numb