版权声明: https://blog.csdn.net/yyy_3y/article/details/82193073
题意:n个数字组成一个环(每个点都有一个价值a ,从任意点开始,每次可以跳k步,一共可以跳m次,问最少需要补充多少价值,才能使价值达到s。
思路:
1)首先,显然,对于每个数字只可能在一个环中。所以我们只需要开一个数组维护一下是否访问过就行,这样就可以预处理出每个循环节。
2)对于每个循环节,我们计算出可以循环几圈,讨论一下一圈的正负,计算一下余数对最后答案的影响。
3)这样就会有一个模型:现在有n个数字,求小于等于m个数字的连续的最大字段和。
可以用单调队列维护前缀和的最小值,因为当前的sum[i]-单调队列维护的最小sum[j]能保证对于当前的i最优。
#include<bits/stdc++.h>
#define debug(a) cout << #a << " " << a << endl
#define lnn putchar('\n')
#define see putchar(' ')
#define LL long long
#define ull unsigned long long
#define PI acos(-1.0)
#define eps 1e-6
const int N=2e5+7;
using namespace std;
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
LL a[N],vis[N];
vector<LL> stk;
LL sum[N];
LL n,s,m,k;
LL q[N];
LL head,rail;
void init()
{
head=1,rail=0;
memset(q,0,sizeof q);
}
void pop(int i,int len)
{
while(i-q[head]>len) head++;
}
void push(int i)
{
while(head<=rail && sum[i]<=sum[q[rail]]) rail--;
}
LL F(int m)
{
int len=stk.size();
for(int i=1;i<=len;i++) sum[i]=sum[i-1]+stk[i-1];
for(int i=1;i<=len;i++) sum[i+len]=sum[len]+sum[i];
for(int i=1;i<=len;i++) sum[i+2*len]=sum[2*len]+sum[i];
init();
LL res=0;
for(int i=1;i<=3*len;i++){
push(i);
q[++rail]=i;
pop(i,m);
if(head<=rail)
res=max(res,sum[i]-sum[q[head]]);
}
return res;
}
int main ()
{
//yyy_3y
//freopen("1.in","r",stdin);
int Case;
int CASE=1;
for(scanf("%d",&Case);Case--;){
scanf("%lld%lld%lld%lld",&n,&s,&m,&k);
for(int i=0;i<n;i++) scanf("%lld",&a[i]);
memset(vis,0,sizeof vis);
LL ans=0;
for(int i=0;i<n;i++){
if(vis[i]) continue;
stk.clear();
int j=i;
while(!vis[j]){
stk.push_back(a[j]);
vis[j]=1;
j=(j+k)%n;
}
LL sum=0;
int sz=stk.size();
for(int i=0;i<sz;i++) sum+=stk[i];
LL x=m%stk.size();
LL y=m/stk.size();
if(y>0){
y--;
x+=sz;
}
LL res=F(x);
ans=max(ans,res);
if(sum>0) res+=y*sum;
ans=max(ans,res);
}
printf("Case #%d: %lld\n",CASE++,max(s-ans,0LL));
}
return 0;
}