HDU4945 2048(dp)

先是看错题意。。然后知道题意之后写了发dp..无限TLE..实在是不知道怎么优化了,跑了遍数据是对的,就当作理论AC掉好了。。

#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
#include <ctime>
using namespace std;

#define ll long long
#define maxn 120000
#define mod 998244353

ll mod_pow(ll a, ll n){
	ll ret = 1;
	while (n){
		if (n & 1) ret = ret*a%mod;
		a = a*a%mod;
		n >>= 1;
	}
	return ret;
}

ll fac[maxn];
ll fac_inv[maxn];

int cnt[2500];
int dp[13][2500];
int two[13] = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048 };
int two_com[13] = { 0, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 };
int n;

inline int getint() {
	int ret = 0; bool ok = 0;
	for (;;) {
		int c = getchar();
		if (c >= ‘0‘&&c <= ‘9‘)ret = (ret << 3) + ret + ret + c - ‘0‘, ok = 1;
		else if (ok)return ret;
	}
}

inline ll comb(int n, int m){
	return fac[n] * fac_inv[m] % mod*fac_inv[n - m] % mod;
}
inline void add(int &a, int b){
	a += b;
	if (a >= mod) a -= mod;
}

int main()
{
	//freopen("1001.in", "r", stdin);
	//freopen("out.txt", "w", stdout);
	//double t1 = clock();
	fac[0] = fac_inv[0] = 1;
	for (int i = 1; i <= 100000; ++i){
		fac[i] = fac[i - 1] * i%mod;
	}
	fac_inv[100000] = mod_pow(fac[100000], mod - 2);
	for (int i = 99999; i >= 0; --i){
		fac_inv[i] = fac_inv[i + 1] * (i + 1) % mod;
	}
	int ca = 0;
	while (~scanf("%d", &n) && n){
		for (int i = 1; i <= 12; ++i) cnt[two[i]] = 0;
		int tmp;
		for (int i = 0; i < n; ++i) {
			tmp = getint();
			cnt[tmp]++;
		}
		int pn = 0;
		for (int i = 1; i <= 12; ++i) pn += cnt[two[i]];
		memset(dp, 0, sizeof(dp)); dp[0][0] = 1;
		ll sum,cb;
		for (int i = 1; i <= 12; ++i){
			int num = cnt[two[i]];
			for (int j = 0; j <= two_com[i - 1]; ++j){
				sum = 0;
				int k;
				for (k = 0; (j >> 1) + k <= two_com[i] && k <= num; ++k){
					cb = comb(num, k);
					sum = sum + cb; if (sum >= mod) sum -= mod;
					add(dp[i][(j >> 1) + k], dp[i - 1][j] * cb%mod);
				}
				if ((j >> 1) + num > two_com[i]){
					ll res = ((mod_pow(2, num) - sum) % mod + mod) % mod;
					add(dp[i][two_com[i]], res*dp[i - 1][j] % mod);
				}
			}
		}
		ll ans = dp[12][1] * mod_pow(2, n - pn) % mod;
		printf("Case #%d: %I64d\n", ++ca, ans);
	}
	//double t2 = clock();
	//cout << t2 - t1 << endl;
	return 0;
}

HDU4945 2048(dp),布布扣,bubuko.com

时间: 2024-10-11 10:59:49

HDU4945 2048(dp)的相关文章

bzoj 3851: 2048 dp优化

3851: 2048 Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 22  Solved: 9[Submit][Status] Description Teacher Mai is addicted to game 2048. But finally he finds it's too hard to get 2048. So he wants to change the rule: You are given some numbers. Every

HDU 4945 2048(DP)

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

Codeforces 413D 2048(dp)

题目连接:Codeforces 413D 2048 题目大意:2048的游戏,两个相同的数x可以变成一个2*x,先给出n,表示在一个1*n的矩阵上面玩2048,规定每次向左移动,并且每次出现一个,给出序列n,表示出现的块的值,0表示既可以是2也可以是4,问说有多少种可能,使得游戏结束后的最大块的值大于等于2^k. 解题思路:dp[i][j][x]表示第i个位置,值为j,x表示先前有没有出现过大于2^k的数: 这种递增的情况可以直接表示为14(总和,以为后面的2,4如果变大,就肯定能和8想合在一起

HDU 4945 2048 DP 组合

思路: 这个题写了一个背包的解法,超时了.搜了下题解才发现我根本不会做. 思路参见这个: 其实我们可以这样来考虑,求补集,用全集减掉不能组成2048的集合就是答案了. 因为只要达到2048就可以了,所以求补集会大大减小枚举的次数. 代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6

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位置时最大

Coder-Strike 2014 - Round2 D 2048 (DP 记忆化搜索)

参考了  http://blog.csdn.net/keshuai19940722/article/details/24723417  他的开头的一点小分析,当然还有题意啦,难得看到CF的题目有点长,看了好久加YY才弄出题意, 但是还是没有推出来状态转移方程,因为题目说向开头移动,我倒着推没有推出来,于是 正着尝试了一把 记忆化搜索,一路搜索过来遇到的只有0,2,4而已,扫到当前一格 还得考虑当前状态的最后一位是否与当前这一位的能够合并,题目要求只有相同的值能合并,这里有一个小技巧,代码里注释了

2014多校8(1001)hdu4945(dp+组合数计数+求逆元)

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

ZOJ 3802 Easy 2048 Again 状压DP

直接从前往后DP,因为一共只有500个数,所以累加起来的话单个数不会超过4096,并且因为是Flappy 2048的规则,所以只有之后数列末尾一串递减的是有效的,因此可以状压. 1700ms = =,据说用滚动数组优化一下会好很多 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector>

ZOJ3802 Easy 2048 Again (状压DP)

ZOJ Monthly, August 2014 E题 ZOJ月赛 2014年8月 E题 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5334 Easy 2048 Again Time Limit: 2 Seconds      Memory Limit: 65536 KB Dark_sun knows that on a single-track road (which means once he passed this