2018 CCPC网络赛 hdu6444 Neko's loop

题目描述:

Neko has a loop of size n.
The loop has a happy value ai on the i−th(0≤i≤n−1) grid. 
Neko likes to jump on the loop.She can start at anywhere. If she stands at i−th grid, she will get ai happy value, and she can spend one unit energy to go to ((i+k)modn)−th grid. If she has already visited this grid, she can get happy value again. Neko can choose jump to next grid if she has energy or end at anywhere. 
Neko has m unit energies and she wants to achieve at least s happy value.
How much happy value does she need at least before she jumps so that she can get at least s happy value? Please note that the happy value which neko has is a non-negative number initially, but it can become negative number when jumping

输入:

The first line contains only one integer T(T≤50), which indicates the number of test cases. 
For each test case, the first line contains four integers n,s,m,k(1≤n≤104,1≤s≤1018,1≤m≤109,1≤k≤n).
The next line contains n integers, the i−th integer is ai−1(−109≤ai−1≤109)

该题关键在于:一个环,环上每点有一个权值,可以从任意点开始走,问至多走m步情况下所经过点的权值和最大是多少。主要比较难想的在于O(nlogn)地求一个环上至多长为k的字段和的最大值。

主要思路:可以在扫一遍的过程中一个个地求以i为结尾的至多长为k的字段和的最大值。维护一个单调队列,保证队头一直是点{i-k..i-k+1....i-i}的前缀和中的最小值,i的前缀和减去该最小值即为i为结尾的至多长为k的字段和的最大值。

          单调队列的维护:1.若队头的时间戳与i距离大于k,则队头出队。2.每次将i的前缀和入队的时候,循环进行操作:队尾若大于i的前缀和则队尾出队。

#include<bits/stdc++.h>
#define rep(i,a,b) for(long long i=a;i<=b;++i)
using namespace std;
long long n,m,s,k;
const long long MAXN=1e4+10;
long long a[MAXN];
void Input()
{
    scanf("%lld%lld%lld%lld",&n,&s,&m,&k);
    rep(i,0,n-1) scanf("%lld",a+i);
}
long long gcd(long long a,long long b)
{
    return b==0?a:gcd(b,a%b);
}
long long ring[MAXN];
long long head;
long long vis[MAXN];
long long pre[MAXN];
void init()
{
    memset(vis,0,sizeof(vis));
}
int tail=0;
struct Qu
{
    long long t,val;
    Qu() {}
    Qu(long long _val,long long _t)
    {
        t=_t;
        val=_val;
    }
}q[2*MAXN];
void update(long long idx)
{
    Qu one(pre[idx],idx+1);
    while(tail>=head)
    {
        if(q[tail].val>=one.val) tail--;
        else break;
    }
    q[++tail]=one;
}
void debug2(long long i)
{
    printf("i:%lld\n",i);
    rep(i,head,tail)
    {
        printf("val:%lld t:%lld\n",q[i].val,q[i].t);
    }
}
long long calc(long long lim,long long len)
{
  //  printf("lim:%lld\n",lim);
    long long presum=0;
    rep(i,len,2*len-1) ring[i]=ring[i-len];
    rep(i,0,2*len-1)
    {
        presum+=ring[i];
        pre[i]=presum;
       // printf("%lld ",pre[i]);
    }
    head=0;
    tail=0;
    long long maxans=0;
    q[head]=Qu(0,0);
    rep(i,0,2*len-1)
    {
        update(i);

        int nowlen=(i+1)-q[head].t;
        if(nowlen>lim)
        {
            head++;
        }
       // debug2(i);

        //printf("maxans:%lld val:%lld\n",maxans,pre[i]-q[head].val);
        maxans=max(maxans,pre[i]-q[head].val);
    }
    return maxans;

}
void debug(long long len)
{
    rep(i,0,len-1) printf("%d ",ring[i]);
    printf("\n");
}
void work(long long icase)
{
    long long num=gcd(n,k);
    long long ans=0;
    rep(i,0,n-1)
    {
        if(vis[i]) continue;
        head=0;
        long long sum=0;
        long long len=0;
        for(long long j=i;!vis[j];j=(j+k)%n)
        {
           // printf("j:%lld\n",j);
            ring[head++]=a[j];
            sum+=a[j];
            len++;
            vis[j]=1;
        }
        long long time=m/len;
        long long maxseq;
        if(sum<0)
        {
            sum=0;
            maxseq=calc(min(len - 1, m), len);
        }
        else maxseq=calc(m%len,len);
       // debug(len);
        long long other=calc(len-1,len);
        if(m>=len)
        {
            if (other > sum + maxseq){
                long long res = (time-1) * sum;
                long long ians = res + other;
                ans = max(ians,ans);
            }else{
                long long res=time*sum;
                long long ians=res+maxseq;
                ans=max(ians,ans);
            }
        }else{
            long long res=time*sum;
            long long ians=res+maxseq;
            ans=max(ians,ans);
        }
    }
    long long finalans=s-ans;
    if(finalans<0) finalans=0;
    printf("Case #%lld: %lld\n",icase,finalans);
}
int main()
{
    long long T;
    scanf("%lld",&T);
    rep(tt,1,T)
    {
        init();
        Input();
        work(tt);
    }
    return 0;
}
View Code

 

 

 

                

                

posted on 2018-08-27 21:47  缄默火  阅读(372)  评论(0)    收藏  举报

导航