HDU 4945 2048 DP 组合

思路:

  这个题写了一个背包的解法,超时了。搜了下题解才发现我根本不会做。

  思路参见这个

  其实我们可以这样来考虑,求补集,用全集减掉不能组成2048的集合就是答案了。

  因为只要达到2048就可以了,所以求补集会大大减小枚举的次数。

代码:

  

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <string>
 8 #include <queue>
 9 #include <stack>
10 #include <vector>
11 #include <map>
12 #include <set>
13 #include <functional>
14 #include <cctype>
15 #include <time.h>
16
17 using namespace std;
18
19 typedef __int64 ll;
20
21 const int INF = 1<<30;
22 const int MAXN = 1e5+55;
23 const int MAXM = 2055;
24 const ll MOD = 998244353;
25
26 int cnt[MAXM];
27 ll dp[20][MAXM];
28 ll fact[MAXN], inv[MAXN];
29 int n;
30
31 ll myPow(ll x, int d) {
32     ll res = 1;
33     while (d>0) {
34         if (d&1) res = (res*x)%MOD;
35         x = (x*x)%MOD;
36         d >>= 1;
37     }
38     return res;
39 }
40
41 inline ll C(int x, int y) {
42     return ((fact[x]*inv[y])%MOD * inv[x-y])%MOD;
43 }
44
45 inline int lowBit(int x) {
46     return x&(-x);
47 }
48
49 void solve() {
50     int sum = n;
51     for (int i = 0; i < 12; i++) sum -= cnt[1<<i];
52
53     memset(dp, 0, sizeof(dp));
54
55     for (int j = min(2048, cnt[1]); j >= 0; j--) dp[0][j] = C(cnt[1], j);
56
57     for (int i = 1; i < 12; i++) {
58         int cc = 2048>>i;
59         for (int k = min(cc, cnt[1<<i]); k >= 0; k--) { //选k个
60             ll CC = C(cnt[1<<i], k);
61             for (int j = k; j <= cc; j++) { //
62                 dp[i][j] = (dp[i][j] + (((dp[i-1][(j-k)<<1]+dp[i-1][(j-k)<<1|1])%MOD)*CC)%MOD )%MOD;
63             }
64         }
65     }
66
67     ll ans = ((myPow(2, n-sum)-dp[11][0])%MOD+MOD)%MOD;
68     ans = (ans*myPow(2, sum))%MOD;
69     printf("%I64d\n", ans);
70 }
71
72 int main() {
73     #ifdef Phantom01
74         freopen("HDU4945.txt", "r", stdin);
75     #endif //Phantom01
76
77     fact[0] = 1;
78     for (int i = 1; i < MAXN; i++) fact[i] = (fact[i-1]*i)%MOD;
79     inv[MAXN-1] = myPow(fact[MAXN-1], MOD-2);
80     for (int i = MAXN-1; i > 0; i--) inv[i-1] = (inv[i]*i)%MOD;
81
82     int T = 1;
83
84     while (scanf("%d", &n)!=EOF && n!=0) {
85         printf("Case #%d: ", T++);
86         memset(cnt, 0, sizeof(cnt));
87         int x;
88         for (int i = 0; i < n; i++) {
89             scanf("%d", &x);
90             cnt[x]++;
91         }
92         solve();
93     }
94
95     return 0;
96 }

时间: 2024-08-04 18:31:50

HDU 4945 2048 DP 组合的相关文章

HDU 4945 2048(DP)

HDU 4945 2048 题目链接 题意:给定一个序列,求有多少个子序列能合成2048 思路:把2,4,8..2048这些数字拿出来考虑就能够了,其它数字不管怎样都不能參与组成.那么在这些数字基础上,dp[i][j]表示到第i个数字,和为j的情况数,然后对于每一个数枚举取多少个,就能够利用组合数取进行状态转移,这里有一个剪枝,就是假设加超过2048了,那么后面数字的组合数的和所有都是加到2048上面,能够利用公式一步求解,这种整体复杂度就能够满足题目了.然后这题时限卡得紧啊.10W内的逆元不先

HDU 4945 2048(dp+快速幂取模)

题目大意:给你一个序列让你求出有多少种组合可以得到2048.结果要对998244353取余. 解题思路:求出不能满足条件的方案数,然后用总的减去不满足的然后乘上其他无关的组合方式,比如3,5这些数字是在构成2048的过程中无用的,所以乘上这些组合出来的情况. dp[i][j]表示取到第i个2^i的数,其最大的和在j*2^i至(j+1)*2^i-1的方案数. 所以有dp[i][j] += ((dp[i-1][k]+dp[i-1][k+1])*use[i][j-k/2])%mod.表示在i位置时最大

hdu 4945 2048 (dp+组合数)

2048 Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 840    Accepted Submission(s): 199 Problem Description Teacher Mai is addicted to game 2048. But finally he finds it's too hard to get 2048.

HDU 4945 2048(dp)

题意:给n(n<=100,000)个数,0<=a[i]<=2048 .一个好的集合要满足,集合内的数可以根据2048的合并规则合并成2048 .输出好的集合的个数%998244353 . 比赛的时候想着1跟3可以合并成4 ....然后就越搞越复杂了.....2048玩得不多的我没有透彻的合并规则概念..... 看了题解写了发,妥妥地TLE...本地随意n=100,000都TLE了... 用dp[i][j]表示当前 i个2^j 的方案数 然后队友提醒优化,就是,当枚举到比如,value =

hdu 5396 区间dp+组合

http://acm.hdu.edu.cn/showproblem.php?pid=5396 Problem Description Teacher Mai has n numbers a1,a2,?,anand n?1 operators("+", "-" or "*")op1,op2,?,opn?1, which are arranged in the form a1 op1 a2 op2 a3 ? an. He wants to erase

2014多校联合八(HDU 4945 HDU 4946 HDU 4948 HDU 4950 HDU 4951 HDU 4952)

HDU 4945 2048 题意:给你一堆数字  问有几个子集可以拼出2048 思路: 拼数字的规则相当于让数字乘二  所以不是2^i的数字不会拼出2048  那么这些数可选可不选  即为2^cnt种可能 之后只要计算出有几个子集不可能拼出2048即可  不过简单的直接dp是2048*100000的复杂度的  会TLE 所以要变成先枚举元素  再枚举该种元素个数  再枚举2048种状态  然后利用组合求(组合里需要逆元) 为什么这样快?  因为比如枚举2^5这个元素的时候  最多取2^6个  枚

HDU 4832 Chess 排列组合 DP

Chess Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 351    Accepted Submission(s): 124 Problem Description 小度和小良最近又迷上了下棋.棋盘一共有N行M列,我们可以把左上角的格子定为(1,1),右下角的格子定为(N,M).在他们的规则中,"王"在棋盘 上的走法遵循十字

[ACM] hdu 4248 A Famous Stone Collector (DP+组合)

A Famous Stone Collector Problem Description Mr. B loves to play with colorful stones. There are n colors of stones in his collection. Two stones with the same color are indistinguishable. Mr. B would like to select some stones and arrange them in li

HDU 1501 Zipper(DP,DFS)

题意  判断能否由字符串a,b中的字符不改变各自的相对顺序组合得到字符串c 本题有两种解法  DP或者DFS 考虑DP  令d[i][j]表示能否有a的前i个字符和b的前j个字符组合得到c的前i+j个字符  值为0或者1  那么有d[i][j]=(d[i-1][j]&&a[i]==c[i+j])||(d[i][j-1]&&b[i]==c[i+j])   a,b的下标都是从1开始的  注意0的初始化 #include<cstdio> #include<cst