HDU 6205 card card card【最长连续子串+尺取法】

来源:互联网 发布:js二维映射 编辑:程序博客网 时间:2024/05/20 02:54

题目链接

题意:n堆牌,每堆牌有个penalty value,刚开始可以把第一堆牌移到最后面,这个操作可以进行任意多次。然后从第一堆牌开始,每次加上这堆牌的数目减去这堆牌的penalty value,如果这个值小于0则取走到现在为止的所有牌,游戏结束。求刚开始时移第一堆的这个操作进行几次的时候可以拿走的牌最多。

其实就是一个变形版的最长连续子串,保证子串中每个前缀和都大于等于0,如果有一个小于0,这串就直接结束。此外,要保证子串的长度小于等于n。然后如果当前子串长度为n,就减去最开始那个看后面的加上后是否能满足,就是尺取法的思想。

#include <bits/stdc++.h>using namespace std;typedef long long ll;int n;int num[2000000+10];int cha[2000000+10];int main(){    // freopen("1.txt","r",stdin);    while (scanf("%d",&n)!=EOF){        for (int i=1;i<=n;i++){            scanf("%d",&num[i]);        }        for (int i=1;i<=n;i++){            int x;            scanf("%d",&x);            cha[i]=num[i]-x;        }        for (int i=n+1;i<=2*n;i++){            num[i]=num[i-n];            cha[i]=cha[i-n];        }        ll begin=1,len=0,sum=0;        ll tmp=0;        int i=1;        int index=0;        ll MAX=0;        while (i<=2*n){            tmp+=cha[i];            sum+=num[i];            len++;            // printf("%d %lld %lld %lld\n",i,tmp,sum,len);            if (tmp<0){                if (sum>MAX){                    MAX=sum;                    index=begin;                }                begin=i+1;                sum=0;                len=0;                tmp=0;                i++;                continue;            }            else{                if (len==n){                    if (sum>MAX){                        MAX=sum;                        index=begin;                    }                    sum-=num[begin];                    tmp-=cha[begin];                    len--;                    begin++;                }                else{                    if (sum>MAX){                        MAX=sum;                        index=begin;                    }                }                i++;            }        }        if (index>n){            index-=n;        }        index--;        printf("%d\n",index);    }}