Neko's loop
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 795 Accepted Submission(s): 144
Problem Description
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.
Input
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)
Output
For each test case, output one line "Case #x: y", where x is the case number (starting from 1) and y is the answer.
Sample Input
2 3 10 5 2 3 2 1 5 20 6 3 2 3 2 1 5
Sample Output
Case #1: 0 Case #2: 2
题意:给你n个数排列成环(你可以任选一个点作为起点),你最多跳m次,每次跳k个数。跳到一个数就加上这个数字(可以多次跳这个数),求最后最大能得到的值是多少。如果大于s输出0,否则输出s-你的最大值。
思路:找寻环节+长度不超过L的最大子段和。首先用若干个vector存每个循环节的元素。然后对于每个循环节,我们分两种情况讨论:假设循环节长度为sz,循环节总和为sum
1、m不能整除sz。则先计算长度不超过m%sz的最大子段和。然后加上(m/sz)*sum。(在纸上画一下,好好想想)
2、m能整除sz。此时如果按第一种情况考虑的话就相当于固定从第一个点开始跳一直跳完正好(m/sz)个循环节。
所以我们不一定要从第一个点开始跳。于是先求一下长度不超过sz的最大子段和(相当于找一个起点),再加上((m/sz)-1)*sum。(其实我们能使它最大化的地方就是起跳的地方到sz和当前循环节第一个位置到停的地方那两段距离)
然后两种取个最大值就行了。可以直接同时计算两种情况,相当于不能整除的时候最后剩余的几步就不用跳了,整除的时候第一种情况余数为0。
有疑问的地方,欢迎评论区留言。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e4+10;
ll n,m,s,k,len,p;
ll ans,tmp,cnt,ct,tp,f;
vector<ll>vc[maxn];
ll a[maxn],q[maxn],stk[maxn],sum[maxn];
bool vis[maxn];
ll cal(vector<ll>&v,ll tmp)
{
ll res=0;
ll nn=v.size();
ll he=0,ta=0;
for(ll i=0;i<nn;i++) q[i+nn]=q[i]=a[v[i]];
nn*=2;
for(ll i=0;i<nn;i++)
{
if(i==0)sum[i]=q[i];
else sum[i]=sum[i-1]+q[i];
if(i<tmp) res=max(res,sum[i]);//注意我注释的这几个地方,都曾经写错过
while(he<ta&&stk[he]+tmp<i) he++;
if(he<ta)res=max(res,sum[i]-sum[stk[he]]);//
while(he<ta&&sum[stk[ta-1]]>=sum[i]) ta--;
stk[ta++]=i;//
}
return res;
}
ll go(vector<ll>&v,ll m)
{
ll sz=v.size();
ll sm=0;
for(ll i=0;i<sz;i++)
sm+=a[v[i]];
//cout<<"%";
ll len1=m/sz,len2=m%sz;
//cout<<"*";
ll m1=cal(v,len2);
ll m2=cal(v,sz);
m1+=max((ll)0,sm)*len1;
m2+=max((ll)0,sm)*((len1>=1)?(len1-1):0);
return max(m1,m2);
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld%lld",&n,&s,&m,&k);
for(int i=0;i<n;i++)
{
vis[i]=false;
vc[i].clear();
scanf("%lld",&a[i]);
}
cnt=-1;
ans=0;
for(ll i=0;i<n;i++)
if(!vis[i]){
cnt++;
vis[i]=1;
vc[cnt].push_back(i);
for(ll j=(i+k)%n;(j!=i)&&(!vis[j]);j=(j+k)%n)
{
vis[j]=1;
vc[cnt].push_back(j);
}
ans=max(ans,go(vc[i],m));
//cout<<ans<<endl;
}
if(ans>s) ans=0;
else ans=s-ans;
printf("Case #%d: %lld\n",cas++,ans);
}
return 0;
}