BZOJ2815 [ZJOI2012]灾难
BZOJ2816 [ZJOI2012]网络

BZOJ3870 Our happy ending

laekov posted @ 2015年1月28日 20:48 in 未分类 with tags bzoj dp , 597 阅读

立杰出的题,orz。

 

一个时间比较微妙的状压DP。用一个二进制状态表示0~k中哪些数已经可以被表示出来了,然后大于k的数直接乘,因为对状态不产生影响。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define pow2(x) (1<<(x))
#define _l (long long int)

const int maxn = 21;
const int maxb = pow2(maxn) + 9;
const int mod = 1e9 + 7;

int n, k, l, f[2][maxb], zu, va;

#define incm(_a_,_b_) { \
	_a_ +=  _b_; \
	if (_a_ >= mod) \
		_a_ %= mod; \
}

int sov() {
	int prv(0), cur(1);
	memset(f, 0, sizeof(f));
	va = max(0, l - k) + 1;
	zu = pow2(k + 1) - 1;
	f[cur][1] = 1;
	for (int ti = 0; ti < n; ++ ti) {
		swap(cur, prv);
		for (int i = zu; i; -- i)
			f[cur][i] = 0;
		for (int i = zu; i; -- i)
			if (f[prv][i]) {
				for (int j = 1; j <= k; ++ j) {
					int zn((i | (i << j)) & zu);
					incm(f[cur][zn], f[prv][i]);
				}
				incm(f[cur][i], _l f[prv][i] * va % mod);
			}
	}
	int ans(0);
	for (int i = zu, e = pow2(k); i >= e; -- i)
		incm(ans, f[cur][i]);
	return ans;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif

	int t;
	scanf("%d", &t);
	while (t --) {
		scanf("%d%d%d", &n, &k, &l);
		printf("%d\n", sov());
	}
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter