2018 CCPC网络赛 hdu6444 Neko's loop

题目描述:

Neko has a loop of size n.
The loop has a happy value ai on the ith(0in1) grid. 
Neko likes to jump on the loop.She can start at anywhere. If she stands at ith 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(T50), which indicates the number of test cases. 
For each test case, the first line contains four integers n,s,m,k(1n104,1s1018,1m109,1kn).
The next line contains n integers, the ith integer is ai1(109ai1109)

该题关键在于:一个环,环上每点有一个权值,可以从任意点开始走,问至多走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

                

                

猜你喜欢

转载自www.cnblogs.com/zhixingr/p/9545020.html
今日推荐