Neko's loop HDU-6444(网络赛1007)

题意就是给出n个数,在n个数上每次跳k个数,最多可以跳m次,你可以选择跳任意次,也可以都不跳,问你为了达到目标了快乐值至少在开始的需要多少快乐值。

题目可以转换成找出循环节,然后再循环节上疯狂试探我可以得到的最大快乐值,然后减一下。

刚开始想着找循环节,只找了一个,用栈存,然后发现可能会有多个循环节,需要考虑多个循环节的最大值,就转成vector存了。

对于每一个循环节,先找一次长度为m的序列,但是m可能比我的循环节来的大,所以我考虑循环起来。让 y 表示的我循环起来的圈数,y = m / len, x表示剩余的还没走的数,x = m % len,如果一圈可以获得的最大值,我就可以直接加上它,一开始我y圈的快乐值算成了y*sum,然后再去求最后x步的最大快乐值,然后相加,最后错了...炜神给了样例

1

5 1000 30 2

-1 -2 -3 -4 15

这时候我可以循环六圈,但是答案却不是这么算的,因为题目说我可以在任何时候停止,所以我可以在从15开始,到第五圈的15的时候提前结束,这样最后的负数我可以不取到,

所以这时候能直接计算出的最大值只有前y-1圈,然后特判能否循环起来,如果至少可以循环一圈的话,把 x = x + len,对于最后一圈进行特判,求出最后一圈加上剩余一点点步数可以得到的最大的快乐值。然后在相加。

这时候我最后一步的范围就是(0, 2*len),所以能走到的最大范围是(len-1,3*len),所以在求最大连续子串和的时候前缀和的数量应该开三倍空间。然后这题用deque会wa,可能是爆了吧...

#include<map>
#include<set>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lowbit(x) (x & (-x))
#define INOPEM freopen("in.txt", "r", stdin)
#define OUTOPEN freopen("out.txt", "w", stdout)

typedef unsigned long long int ull;
typedef long long int ll;
const double pi = 4.0*atan(1.0);
const int inf = 0x3f3f3f3f;
const ll INF = 1e18+100;
const int maxn = 1e5;
const int maxm = 1e9+10;
const int mod = 1e9+7;
using namespace std;

ll n, m;
int T, tol;
ll s, k;
bool vis[maxn];
ll a[maxn];
ll b[maxn];
ll sum[maxn];
vector<ll> vec[maxn];
struct Node {
    int first;
    ll second;
};
Node q[maxn];

void init() {
    tol = 0;
    memset(q, 0, sizeof q);
    for(int i=0; i<maxn; i++)    vec[i].clear();
    memset(vis, 0, sizeof vis);
}

ll solve(int op, int n, ll m) {
    ll ans = 0;
    memset(sum, 0, sizeof sum);
    for(int i=0; i<n; i++)            sum[i] = i==0 ? vec[op][i] : sum[i-1] + vec[op][i];
    for(int i=n; i<2*n; i++)        sum[i] = sum[i-1] + vec[op][i-n];
    for(int i=2*n; i<3*n; i++)         sum[i] = sum[i-1] + vec[op][i-2*n];
//    for(int i=0; i<3*n; i++)        printf("%lld%c", sum[i], i==3*n-1 ? '\n' : ' ');
    int head = 0;
    int tail = 0;
    for(int i=0; i<3*n; i++) {
        while(head < tail && q[tail-1].second > sum[i-1])    tail--;
        while(head < tail && q[head].first + m < i)          head++;
        q[tail].first = i-1;
        q[tail].second = sum[i-1];
        tail++;
        if(ans < sum[i] - q[head].second) {
            ans = sum[i] - q[head].second;
        }
    }
    return ans;
}

int main() {
    int cas = 1;
    scanf("%d", &T);
    while(T--) {
        init();
        scanf("%lld%lld%lld%lld", &n, &s, &m, &k);
        for(int i=0; i<n; i++)    scanf("%lld", &a[i]);
        for(int i=0; i<n; i++) {
            if(!vis[i]) {
                int pos = i;
                while(!vis[pos]) {
                    vis[pos] = 1;
                    vec[tol].push_back(a[pos]);
                    pos = (pos + k) % n;
                }
                tol++;
            }
        }
//        for(int i=0; i<tol; i++)    for(int j=0; j<vec[i].size(); j++)    printf("%lld%c", vec[i][j], j==vec[i].size()-1 ? '\n' : ' ');
        ll ans = -inf;
        for(int i=0; i<tol; i++) {
            ll res = -inf;
            int len = vec[i].size();
            ll tmp = 0;
            for(int j=0; j<len; j++)    tmp += vec[i][j];
            res = solve(i, len, m);
            ans = max(ans, res);
            if(tmp < 0)    continue;
            ll x = m % len;
            ll y = m / len;
            tmp = max(y-1, 0ll) * tmp;
            if(y >= 1)    x += len;
            res = max(res, solve(i, len, x) + tmp);
            ans = max(ans, res);
        }
        ans = max(0ll, s-ans);
        printf("Case #%d: %lld\n", cas++, ans);
    }
    return 0;
}
View Code

 

posted @ 2018-08-27 16:43  Jiaaaaaaaqi  阅读(209)  评论(0编辑  收藏  举报