HDU 4945 2048(DP)
HDU 4945 2048
题意:给定一个序列,求有多少个子序列能合成2048
思路:把2,4,8..2048这些数字拿出来考虑就能够了,其它数字不管怎样都不能參与组成。那么在这些数字基础上,dp[i][j]表示到第i个数字,和为j的情况数,然后对于每一个数枚举取多少个,就能够利用组合数取进行状态转移,这里有一个剪枝,就是假设加超过2048了,那么后面数字的组合数的和所有都是加到2048上面,能够利用公式一步求解,这种整体复杂度就能够满足题目了。然后这题时限卡得紧啊。10W内的逆元不先预处理出来就超时。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; typedef long long ll;
const int MOD = 998244353; inline void scanf_(int &num)//无负数
{
char in;
while((in=getchar()) > '9' || in<'0') ;
num=in-'0';
while(in=getchar(),in>='0'&&in<='9')
num*=10,num+=in-'0';
} int n, v[2049], mi[15], m, cnt[15];
int dp[15][2049], mi2[100005], invv[100005];
bool istwo[2049]; void init() {
int num;
m = 0;
memset(cnt, 0, sizeof(cnt));
for (int i = 0; i < n; i++) {
scanf_(num);
if (!istwo[num]) {
m++;
continue;
}
else cnt[v[num]]++;
}
} int inv(int n) {
int ans = 1;
int k = MOD - 2;
while (k) {
if (k&1) ans = (ll)ans * n % MOD;
n = (ll)n * n % MOD;
k >>= 1;
}
return ans;
} int solve() {
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= 12; i++) {
for (int j = 0; j <= 2048; j += mi[i]) {
if (dp[i - 1][j] == 0) continue;
int C = 1, s = 0;
int sum = j;
for (int k = 0; k <= cnt[i]; k++) {
int x = sum;
if (x == 2048) {
dp[i][x] = (ll)dp[i - 1][j] * (mi2[cnt[i]] - s) % MOD + dp[i][x];
if (dp[i][x] < 0) dp[i][x] += MOD;
if (dp[i][x] >= MOD) dp[i][x] -= MOD;
break;
}
if (x % mi[i + 1])
x = x - mi[i];
dp[i][x] = (ll)dp[i - 1][j] * C % MOD + dp[i][x];
if (dp[i][x] >= MOD) dp[i][x] -= MOD;
s += C;
if (s >= MOD) s -= MOD;
C = (ll)C * (cnt[i] - k) % MOD * invv[k + 1] % MOD;
sum += mi[i];
}
}
}
return (ll)dp[12][2048] * mi2[m] % MOD;
} int main() {
memset(istwo, false, sizeof(istwo));
memset(v, -1, sizeof(v));
mi[0] = 0; v[0] = 0;
for (int i = 1, j = 1; i <= 2048; i *= 2, j++) {
istwo[i] = true;
v[i] = j;
mi[j] = i;
}
mi[13] = 4096;
for (int i = 1; i <= 2048; i++) {
if (v[i] == -1)
v[i] = v[i - 1];
}
mi2[0] = 1;
for (int i = 1; i <= 100000; i++) {
invv[i] = inv(i);
mi2[i] = mi2[i - 1] * 2 % MOD;
}
int cas = 0;
while (~scanf("%d", &n) && n) {
init();
printf("Case #%d: %d\n", ++cas, solve());
}
return 0;
}
HDU 4945 2048(DP)的更多相关文章
- HDU 4945 2048 DP 组合
思路: 这个题写了一个背包的解法,超时了.搜了下题解才发现我根本不会做. 思路参见这个: 其实我们可以这样来考虑,求补集,用全集减掉不能组成2048的集合就是答案了. 因为只要达到2048就可以了,所 ...
- HDU 4945 2048(dp)
题意:给n(n<=100,000)个数,0<=a[i]<=2048 .一个好的集合要满足,集合内的数可以根据2048的合并规则合并成2048 .输出好的集合的个数%998244353 ...
- hdu 4945 2048 (dp+组合的数目)
2048 Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submi ...
- HDU 4945 (dp+组合数学)
2048 Problem Description Teacher Mai is addicted to game 2048. But finally he finds it's too hard to ...
- hdu 4123 树形DP+RMQ
http://acm.hdu.edu.cn/showproblem.php? pid=4123 Problem Description Bob wants to hold a race to enco ...
- hdu 4507 数位dp(求和,求平方和)
http://acm.hdu.edu.cn/showproblem.php?pid=4507 Problem Description 单身! 依旧单身! 吉哥依旧单身! DS级码农吉哥依旧单身! 所以 ...
- hdu 3709 数字dp(小思)
http://acm.hdu.edu.cn/showproblem.php?pid=3709 Problem Description A balanced number is a non-negati ...
- hdu 4352 数位dp + 状态压缩
XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- hdu 4283 区间dp
You Are the One Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
随机推荐
- Javascipt数组去重的几种方式
方法一 function unique(arr) { var retArr = []; for (var i = 0; i < arr.length; i++) { (retArr.indexO ...
- 【Hibernate步步为营】--复合主键映射具体解释
上篇文章讨论了继承映射,它是对象模型中最主要的特性,对于继承映射它的主要区分是字段类型的不同,所以在生成表结构时须要有新列来标识数据的类型,能够使用<subclass>标签并在标签中加入d ...
- Python标准库:内置函数format(value[, format_spec])
的值的函数value按format_spec的格式来格式化,然而函数解释format_spec是依据value的类型来决定的.不同的类型有不同的格式化解释. 当參数format_spec为空时,本函数 ...
- python派QQ邮件
#encoding=utf-8 __author__ = 'ds' #文件名冲突 from email.mime.text import MIMEText import smtplib if __na ...
- LeetCode——Linked List Cycle II
Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Foll ...
- Codeforces 514 D R2D2 and Droid Army(RMQ+二分法)
An army of n droids is lined up in one row. Each droid is described by m integers a1, a2, ..., am, w ...
- idea_intellij
近期要研读和调试spark2,用eclispe据说各种问题,so还是切换到 intellij 1:下载 (官网自行下载最新版本) 2: 注册码 intellij idea 2016 activati ...
- Office——检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件时失败
检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 8000401a 1.运行dcomcnfg.e ...
- hive union all 使用
功能:将两个表中的 同样的字段拼接到一起 測试: create external table IF NOT EXISTS temp_uniontest_ta ( a1 string, a2 strin ...
- NOIP 2012 解决问题的方法
[D1T1vigenerepassword] P1778vigenerepassword Accepted 标签:[显示标签] 描写叙述 16世纪法国外交家Blaise de Vigenère设计了一 ...