hdu 6444 Neko's loop 单调队列+暴力处理循环节

版权声明:本文为博主原创文章,转载请附上原博客链接。 https://blog.csdn.net/Dale_zero/article/details/82086353

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6444

先用O(n)暴力处理出每个循环节存到数组中,同时维护数组的和,再对每一个循环节作如下处理。

如果循环节的和>0,则最后的答案要加上sum*((m%len)-1)。再用单调队列处理m%len+len长度的区间长度为m的前缀和最小值。在此过程中不断更新以i为结尾的最大连续子区间和。最后更新ans值。

如果ans大于s,则说明初始的happy value可以为0,输出0。

否则输出s-ans。

#include<bits/stdc++.h>
#define inf (1LL<<60)
#define mod 1000000007
#define For(i,m,n) for(int i=m;i<=n;i++)
#define Dor(i,m,n) for(int i=m;i>=n;i--)
#define LL long long
#define lan(a,b) memset(a,b,sizeof(a))
#define sqr(a) a*a
using namespace std;

vector<LL> b[10010];
LL a[10010];
int num1[10010];
LL c[10010];
LL sum1[10010];

int main()
{
    int t;
    scanf("%d",&t);
    For(tt,1,t)
    {
        int n,mm,k;
        LL s;
        lan(sum1,0);
        lan(a,0);
        lan(num1,0);
        lan(c,0);
        lan(sum1,0);
        scanf("%d%lld%d%d",&n,&s,&mm,&k);
        For(i,1,n)
            b[i].clear();
        For(i,0,n-1)
            scanf("%lld",&a[i]);
        int vis[10100]={0};
        int tot=1;
        For(i,0,n-1)
        {
            if(vis[i]==1)
                continue;
                int j=i;
            while(vis[j]==0)
            {
                vis[j]=1;
                b[tot].push_back(a[j]);
                sum1[tot]+=a[j];
                j=(j+k)%n;
            }
            tot++;
        }
        LL ans=0;
        For(i,1,tot-1)
        {
            int m=mm;
               int len=b[i].size();
                LL sum=0;
                if(sum1[i]>0)
                sum=(1LL*(m/len)-1)*sum1[i];
                m%=len;
                m+=len;
//               printf("b%lld:\n",i);
//               For(j,0,len-1)
//               printf("%ld ",b[i][j]);
//               puts("");
               LL maxx=-inf;
               int h1=0,t1=0;
               LL pre=0;
               For(j,0,len+m)
               {
                   LL bij;
                   if(j>=len)
                   {
                        if(j%len==0)
                            bij=b[i][0];
                    else if(j>len)
                        bij=b[i][j%len];
                   }
                   else
                   bij=b[i][j];
//                   printf("bij=%lld pre=%lld\n",bij,pre);
                    bij+=pre;
                    pre=bij;
//                   printf("j=%d b[%d]=%lld\n",j,j,bij);
                   int tem=j;
                    while(h1<t1&&c[t1-1]>bij) t1--;
                    c[t1++]=bij;
                    num1[t1-1]=tem;
                    while(tem-num1[h1]>m) h1++;
//                    printf("h1=%d t1=%d\n",h1,t1);
//                   For(p,h1,t1-1)
//                   printf("%lld ",c[p]);
//                   puts("");
                    if(tem>=m-1)
                        maxx=max(maxx,bij-c[h1]);
//                        printf("maxx=%d\n",maxx);
               }
            ans=max(ans,maxx+sum);
//            printf("ans=%lld\n",ans);
        }
//            printf("ans=%lld s=%lld\n",ans,s);
        if(ans>s)
            printf("Case #%d: 0\n",tt);
        else
            printf("Case #%d: %lld\n",tt,s-ans);
    }
    return 0;

}
//100
//6 100 12 5
//1 2 3 4 -5 6

猜你喜欢

转载自blog.csdn.net/Dale_zero/article/details/82086353
今日推荐