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 ...
随机推荐
- springMvc的注解注入方式
springMvc的注解注入方式 最近在看springMvc的源码,看到了该框架的注入注解的部分觉的有点吃力,可能还是对注解的方面的知识还认识的不够深刻,所以特意去学习注解方面的知识.由于本人也是抱着 ...
- Cocos2d-x 脚本语言Lua使用
Cocos2d-x 脚本语言Lua使用 前面几篇博客已经把Lua的相关基础知识介绍了.本篇博客就来介绍一下,怎样在Cocos2d-x项目中使用Lua这门脚本语言进行开发.因为笔者使用的时Mac系统.所 ...
- MVC中使用泛型仓储模式和依赖注入
在ASP.NET MVC中使用泛型仓储模式和依赖注入,实现增删查改 原文链接:http://www.codeproject.com/Articles/838097/CRUD-Operations-Us ...
- JavaScript中的各种奇葩问题
原文:JavaScript中的各种奇葩问题 JavaScript浮点数 var a = (0.1 + 0.2) + 0.3; var b = 0.1 + (0.2 + 0.3); console.lo ...
- Intel 80x86 寻址模式
随着进一步的研究,我们会逐渐接触到你的电脑配置模式的内在联系,和设计原则.在这些,解决计算机是一个非常重要的概念,我们需要很好地理解了什么. 一.预赛: (1)作数 在接触寻址方式之前,我们还要先了解 ...
- Nyoj 吝啬的国度(图论&&双DFS)
描述在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来.现在,Tom在第S号城市,他有张该国地图,他想知道如果自己要去参观第T号城市,必须经过的前一个城市是几号城市(假设你 ...
- 使用C#实现顺序队列
队列(Queue)是插入操作限定在表的尾部而其它操作限定在表的头部进行的线性表.把进行插入操作的表尾称为队尾(Rear),把进行其它操作的头部称为队头(Front).当对列中没有数据元素时称为空对列( ...
- C# 反射技术应用
反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的 ...
- StyleCop中有一些官方自己写好的检测规则下面就是英文的解释
在StyleCop中有一些官方自己写好的检测规则下面就是英文的解释 文档规则 1.SA1600:ElementsMustBeDocumented元素必须添加注释 2.SA1601: PartialEl ...
- java-新浪微博开放平台——话题跟踪
代码 网盘地址:http://pan.baidu.com/s/1pJ1D0Kz