【Kickstart】2018 Round D - Candies

解法

首先,跟区间和和滑动窗口有关系
计算区间和,首先要把前缀和算出来
总之,要先固定一个区间的端点,可以是左,也可以是右。假如我固定的是左端点l,要找合适的右端点r
要保证这个区间奇数个数不超过o
然后需要找到r,使得P[r]-P[l-1]是满足P[r]-P[l-1]<=d且最大的那个,也就是说,P[r]要是不超过P[l-1]+d但最接近它的一个
这个得用upper_bound来做(如果固定的是右端点就是lower_bound
在C++里用multiset可以做(因为窗口里可能有相同的值!),删除的时候记得相同的值只能删除一个!#include <stdio.h>

这里的滑动窗口可以用双指针实现,当l增加1的时候,r只可能增加不可能减少,所以就是类似于尺取法。

#include <stdio.h>
#include <string>
#include <iostream>
#include <memory.h>
#include <stdlib.h>
#include <set>
#include <cmath>
#include <vector>
#include <algorithm>

#define MAXN 500010
#define NINF 0x8000000000000000
#define INF 1000000010

using namespace std;

typedef long long lld;

lld A[MAXN],P[MAXN];
multiset<lld> minV;

void solve(lld n,lld o, lld d) {
    P[0]=0;
    for(int i=1;i<=n;++i)
        P[i] = P[i-1]+A[i];
    minV.clear();
    lld ans = NINF;
    lld odds = 0;
    int l=1,r=l;
    for(;l<=n;++l) {
        r = max(r,l);
        while(r<=n) {
            if(A[r]%2==0) minV.insert(P[r]);
            else {
                if(odds<o) {
                    minV.insert(P[r]);
                    odds++;
                } else break;
            }
            r++;
        }
        auto it = minV.upper_bound(d+P[l-1]);
        if(it!=minV.begin()) {
            it--;
            ans = max(*it-P[l-1],ans);
        }
        if(l<r) {
            if(A[l]%2!=0) odds--;
            minV.erase(minV.find(P[l]));
        }
    }
    if(ans==NINF) printf("IMPOSSIBLE\n");
    else printf("%lld\n",ans);
}

int main() {
//    freopen("obj.txt","r",stdin);
//    freopen("my.out","w",stdout);
    int t;
    scanf("%d",&t);
    for(auto round=1;round<=t;++round) {
        lld n,o,d,x1,x2,a,b,c,m,l;
        scanf("%lld%lld%lld",&n,&o,&d);
        scanf("%lld%lld%lld%lld%lld%lld%lld",&x1,&x2,&a,&b,&c,&m,&l);
        A[1] = x1+l;
        A[2] = x2+l;
        for(int i=3;i<=n;++i) {
            lld tmp = x2;
            x2 = (a*x2%m+b*x1%m+c)%m;
            x1 = tmp;
            A[i] = x2+l;
        }
        printf("Case #%d: ",round);
        solve(n,o,d);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值