题目链接: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