1 条题解
-
0
自动搬运
来自洛谷,原作者为

耶梦加得
In the end it doesn't even matter.搬运于
2025-08-24 22:35:56,当前版本为作者最后更新于2022-02-07 16:48:16,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
由于按了 Command+Q 导致没能晋级的选手报到大眼观察, 这么小,复杂度很可能和 有关,然后 也很小,所以复杂度很可能是 之类的。又是有限制的,“答案可能很大”的计数,八成是 DP 没跑了。
显然我们有一个状态是“当前处理到第 头牛”。考虑从 到 的转移过程,容易发现此时 的牛应当都处于同一饥饿值,否则无论如何对 操作都无法满足条件。
也就是说,还有两个状态分别是牛 的饥饿值 ,以及牛 的饥饿值 。空间 ,爆炸。
仔细考虑,容易发现其实我们只关心这两个值的差值。对于整个 DP 过程而言 的值一旦确定就无法改变。我们可以将 DP 分若干次次进行,每一次人为规定每一头奶牛最终的饥饿值为 。设 ,易知 。对于每一次 DP,先把所有 都减去 。
那么规定 表示前 头牛使得:
- 前 头牛饥饿值为 0(注意:在减去 的意义下);
- 第 头牛饥饿值为 。
考虑转移,由于考虑 的时候我们要把第 头牛也喂饱,也就是对于 ,要先对 两头牛投喂 次,因此 。容易得到转移方程:
$dp[i + 1][j] = \sum{dp[i][j']}(0 \le j \le \min(H_i,H_{i+1}-j)$
边界为 ,要求 。
可以通过处理前缀和的方式 转移,DP 复杂度 ,总复杂度 ,空间上可以通过滚动数组进一步优化(代码没有用滚动数组)。
最后输出 的总和然后发现样例都过不去,交一发 WA50。对于样例 输出 数组,发现我们第一次 DP 就得出了 。
冷静分析题目,发现题目问的是有多少种初始情况,而不是有多少种方案。当 为偶数时, 为多少不重要(可以通过 次操作变成 ),因此我们对于这种情况进行一次 DP 后直接输出 即可。
#include<algorithm> #include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<vector> using namespace std; inline int mmin(register int x, register int y) { return x > y ? y : x; } const long long mod = 1000000007; int n; int a[107], mn = 1000; long long ans, g[107][1007]; signed main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%d", a + i); mn = mmin(mn, a[i]); } for(int i = 0; i <= a[1]; ++i) g[1][i] = i + 1; //这里省略了求和 if(n % 2 == 0)mn = 0; for(int d = 0; d <= mn; ++d) { for(int i = 2; i <= n; ++i) { g[i][0] = g[i - 1][mmin(a[i], a[i - 1]) - d]; for(int j = 1; j <= a[i] - d; ++j) { g[i][j] = g[i][j - 1] + g[i - 1][mmin(a[i] - j, a[i - 1]) - d]; if(g[i][j] >= mod) g[i][j] -= mod; } } ans += g[n][0]; if(ans >= mod) ans -= mod; } printf("%lld\n", ans); return 0; }
- 1
信息
- ID
- 7463
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者