5 November
拓扑排序
for (int i=1; i<=n; ++i) if (!ind[i]) q.push(i);
while (!q.empty()) {
int now=q.top(); q.pop(); printf("%d ", now);
for (int k=head[now]; k; k=nex[k])
if (--ind[to[k]]==0) q.push(to[k]);
}
神奇の背包 DP
现有 \(N\) 个物品和容积为 \(M\) 的背包. 物品的体积分别为 \(V_1, V_2, ..., V_N\). 求不选取物品 \(i\) 时, 装满背包的方案数量.
设 \(f(n, V)\) 为正向枚举的背包, \(g(n, V)\) 为反向枚举的背包, 则方案数为 \(\displaystyle \sum_{i=1}^{n}\sum_{j=0}^{m} f(i-1, j)\cdot g(i+1, m-j)\).
本次错误在于没有搞明白1维和2维背包的代码异同点:1维背包已经无需直接赋值,2维背包还是需要 \(f(i, j)=f(i-1, j)\) 的。
#include <cstdio>
int n, m, w[1003], f[1003][10003], g[1003][10003], ans;
int main() {
scanf("%d%d", &n, &m);
for (int i=1; i<=n; ++i) scanf("%d", &w[i]);
f[0][0]=1;
for (int i=1; i<=n; ++i) {
for (int j=m; j>=w[i]; --j) f[i][j]=(f[i-1][j]+f[i-1][j-w[i]])%1014;
for (int j=w[i]-1; ~j; --j) f[i][j]=f[i-1][j]; // (*)
}
g[n+1][0]=1;
for (int i=n; i; --i) {
for (int j=m; j>=w[i]; --j) g[i][j]=(g[i+1][j]+g[i+1][j-w[i]])%1014;
for (int j=w[i]-1; ~j; --j) g[i][j]=g[i+1][j]; // (*)
}
for (int i=1; i<=n; ++i) {
ans=0;
for (int j=0; j<=m; ++j) ans=(ans+f[i-1][j]*g[i+1][m-j])%1014;
printf("%d ", ans);
}
return 0;
}
Sequence
给出数列 \(\{A_n\}\), 修改最少的元素, 使得数列 \(\{A_n\}\) 成为一个公差为 1 的等差数列.
预处理成数列 \(\{A_n-n\}\) 即可极大简化本题解法.
Post author 作者: Grey
Copyright Notice 版权说明: Except where otherwise noted, all content of this blog is licensed under a CC BY-NC-SA 4.0 International license. 除非另有说明,本博客上的所有文章均受 知识共享署名 - 非商业性使用 - 相同方式共享 4.0 国际许可协议 保护。