BZOJ3827: [Poi2014]Around the world && CF526E Transmitting Levels
要求的东西是一样的,感觉 poi 的题面要比 cf 的题面容易想一些
首先贪心的从每个点往后尽可能跳的远,
如果能跳肯定是越远越好,如果不能跳那无论如何都不合法了
先破环成链
从前往后每个点能跳到的最远位置显然是单调的,可以 O(n) 求
为了便于思考,倒着考虑,计算从一个点往回能到哪
这是和正着做是一样的,想要能到一个点只要能跳过他就行
正着计算只要倒着推应该也是可以的
每个点向前唯一对应一个来的点,像是一个树形结构(有的题解是这么写的反正我也没想到)
这样方便从前往后顺序枚举并从前边的状态转移过来,f[i] = f[pre_i] + 1
设复制的一段都是终止点,之前的一段都是起始点
这样就可以递推出解了,没有什么决策的
只要从后面一段开始计算最远往前能到哪就好了,每次从前边的继承
每次判断一下从这个位置往前最远能到的位置距离这里是不是超过 n 个了
如果是的话,取最小值?
其实直接输出答案就行了,证明看这里吧
代码:
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cctype> #include <cstdio> using namespace std; const int MAX_N = 2000001; int n, m, max_val; int pre_sum[MAX_N], bgn[1000001]; int f[1000001]; inline int rd() { register int x = 0, c = getchar(); while (!isdigit(c)) c = getchar(); while (isdigit(c)) { x = x * 10 + (c ^ 48); c = getchar(); } return x; } int main() { n = rd(); m = rd(); register int v1, v2, v3, v4; for (int i = 1; i + 3 <= n; i += 4) { pre_sum[i] = pre_sum[i - 1] + (v1 = rd()); pre_sum[i + 1] = pre_sum[i] + (v2 = rd()); pre_sum[i + 2] = pre_sum[i + 1] + (v3 = rd()); pre_sum[i + 3] = pre_sum[i + 2] + (v4 = rd()); max_val = max(max_val, max(v1, max(v2, max(v3, v4)))); } for (int i = ((n >> 2) << 2) + 1; i <= n; ++i) { pre_sum[i] = pre_sum[i - 1] + (v1 = rd()); max_val = max(max_val, v1); } int maxi = (n << 1); for (int i = n + 1; i <= maxi; ++i) pre_sum[i] = pre_sum[i - 1] - pre_sum[i - n - 1] + pre_sum[i - n]; int d, lef; while (m--) { d = rd(); lef = 1; if (max_val > d) { puts("NIE"); continue; } for (int i = n + 1; i <= maxi; ++i) { while (pre_sum[i] - pre_sum[lef] > d) ++lef; if (lef > n) { f[i - n] = f[lef - n] + 1; bgn[i - n] = bgn[lef - n]; } else { f[i - n] = 1; bgn[i - n] = lef; } if (i - bgn[i - n] >= n) { printf("%d\n", f[i - n]); break; } } } return 0; }
禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载
,用户转载请注明出处:https://www.cnblogs.com/xcysblog/