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;
}    

  

posted @ 2018-11-02 08:10  EvalonXing  阅读(228)  评论(0编辑  收藏  举报