专栏文章

题解:P1329 数列

P1329题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqazcwb
此快照首次捕获于
2025/12/04 01:50
3 个月前
此快照最后确认于
2025/12/04 01:50
3 个月前
查看原文
dpi,jdp_{i,j} 表示 k=1iak=j\sum_{k=1}^i a_k=j 的方案数。转移是平凡的,与背包问题类似。
暴力的做法:假设所有数都是前一个数加一,即构造 ai=i1a_i=i-1,总和就是 n(n1)/2n(n-1)/2。将 aia_i22 会使所有数总和减少 2(ni+1)2(n-i+1),所以目标就是用不同的 (ni+1)(n-i+1) 凑出 goal=sn(n1)/2goal=s-n(n-1)/2。这么做时间复杂度是 O(2n)O(2^n) 的,但可以用来输出方案(所以就出现了一道题正解中同时使用正解和暴力做法的情况)。
CPP
const ll N = 2000, S = 6000;
const lll mod = (lll)(1) << 64;
lll dp[N][S];
ll n, s, goal, cnt, ch[N];

void dfs(ll p, ll cur) {
	if (cur > goal)
		return;
	elif(p > n) {
		if (cur == goal) {
			cnt++;
			ll sum = 0;

			rep(i, 1, n) {
				sum += ch[i];
				cout << sum << ' ';
			}

			endl;

			if (cnt >= 100)
				exit(0);
		}
	} else {
		ch[p] = -1;
		dfs(p + 1, cur + (n - p + 1));
		ch[p] = 1;
		dfs(p + 1, cur);
	}
}

int main() {
	cin >> n >> s;

	if (abs(s) > n * (n - 1) / 2 or (n * (n - 1) / 2 - s) % 2) {
		cout << 0;
		return 0;
	}

	goal = (n * (n - 1) / 2 - s) / 2;
	dp[1][0] = 1;

	rep(i, 2, n) {
		ll dis = n - i + 1;
		cpy(dp[i], dp[i - 1]);

		rep(j, dis, S - 1) (dp[i][j] += dp[i - 1][j - dis]) %= mod;
	}

	cout << (ull)(dp[n][goal]) << '\n';
	dfs(2, 0);
}
代码宏定义在我个人空间自取。

评论

0 条评论,欢迎与作者交流。

正在加载评论...