K - card card card HDU - 6205

题目网址点击打开链接

    题目大意给你n堆牌,每一堆牌有对应的牌数ai以及惩罚值bi,然后就做个游戏,从第一堆开始拿,把ai张牌都摊开正面朝上,然后要求再把bi张牌翻转,如果你此时手头的正面朝上的牌的数量>=此时需要翻转的牌的数量,就继续拿下一堆,直到n堆牌都取完了或者是取到某堆牌时,此时手头的正面朝上的牌的数量<此时需要翻转的牌的数量,那么游戏结束,你可以拿到第一堆到目前这一堆的所有牌。然后又说你可以把第一堆的牌放到最后面,问最少要进行多少次这样的操作,可以取得最多的牌。

    做法就是把a数组和b数组都倍增,a[i+n]=a[i](0<=i<=n-1),这样的话执行一次移动操作,我们不用真的移动,我们只需要把长度为n的区间往右边移动一个位子就可以了,比如说移动一次,这n个数的第一个数就变成a[1]了,然后从a[1]遍历到a[n].因为求的是最少的操作次数,所以操作次数从0到n-1.最多次数是n-1,是因为次数大于n-1的话,得到的序列就开始重复了。操作次数是多少,区间起点位置就是多少,用sum记录从区间起点到目前获取的牌总数,num来记录从区间起点到现在这堆牌的suma-sumb的差,如果num<0了表示游戏结束,更新一下信息,记录下目前这堆牌的位置,然后下次遍历的区间的起点就是这堆牌的位置+1了。然后还要特判一下,游戏结束的时候有没有把n堆牌取完,有的话就打印此时的操作次数。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int main()
{
    long long a[2*maxn],b[2*maxn],n,tempans,ans,sum,num,j,lastend,maxx=-1;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%lld",&a[i]);
            a[i+n]=a[i];
        }
        for(int i=0;i<n;i++)
        {
            scanf("%lld",&b[i]);
            b[i+n]=b[i];
        }
        for(tempans=0;tempans<n;tempans=lastend+1)
        {
            sum=0;
            num=0;
            for(j=tempans;j<(tempans+n);j++)
            {
                sum+=a[j];
                num+=(a[j]-b[j]);
                if(num<0)
                {
                    lastend=j;
                    if(sum>maxx)
                    {
                        maxx=sum;
                        ans=tempans;;
                    }
                    break;
                }

            }
            if(j==(tempans+n))
            {
                ans=tempans;
                break;
            }

        }
        printf("%lld\n",ans);
    }
        return 0;

}

posted @ 2018-07-08 12:17  eason99  阅读(81)  评论(0编辑  收藏  举报