Neko’s loop
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
Problem Description
Neko has a loop of size n.
The loop has a happy value ai on the i−th
grid.
Neko likes to jump on the loop.She can start at anywhere. If she stands at i−th grid, she will get
happy value, and she can spend one unit energy to go to ((i+k)mod n)−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
unit energies and she wants to achieve at least
happy value.
How much happy value does she need at least before she jumps so that she can get at least
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
, which indicates the number of test cases.
For each test case, the first line contains four integers
The next line contains n integers, the i−th integer is
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
思路:对于每个起点 ,走若干步后都会回到起点,即每个 属于其中一个循环节。
求出每个循环节里的数,然后枚举循环节里的起点,求行走获得的快乐最大值。
那么对于行走可能有2种选择:
假设循环节长度为 。
一种是先走 圈循环(如果走一圈的快乐值总和大于0),然后对于剩下的 % 步,我们可以用单调队列求其最值。
还有一种是如果
,则先用单调队列求出走
步以内可以获得的最值,
假设在
步以内需要
步才能得到最大值,然后用这个最大值加上
。
然后对这2种选择取最大值。
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e4+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
ll a[MAX];
ll sum[MAX];
int v[MAX];
vector<ll>p;
deque<int>que;
ll cal(ll m)
{
int len=p.size();
for(int i=0;i<len;i++)p.push_back(p[i]); //扩大2倍
for(int i=0;i<p.size();i++)sum[i]=(i==0?p[i]:sum[i-1]+p[i]);
int y=m%len;
ll ans=0;
while(!que.empty())que.pop_back();
for(int i=0,R=0;i<len;i++) //先走m/len圈
{
while(!que.empty()&&que.back()<i)que.pop_back();
while(R<=i+y-1)
{
while(!que.empty()&&sum[que.front()]<=sum[R])que.pop_front();
que.push_front(R);
R++;
}
int x=que.back();
ll res=max(0ll,sum[x]-(i==0?0:sum[i-1]));
ans=max(ans,res+max(0ll,m/len*sum[len-1]));
}
if(m>=len) //先找到最大值所需步数x,再走(m-x)/len圈
{
while(!que.empty())que.pop_back();
for(int i=0,R=0;i<len;i++)
{
while(!que.empty()&&que.back()<i)que.pop_back();
while(R<=i+len-1)
{
while(!que.empty()&&sum[que.front()]<=sum[R])que.pop_front();
que.push_front(R);
R++;
}
int x=que.back();
ll res=max(0ll,sum[x]-(i==0?0:sum[i-1]));
ans=max(ans,res+max(0ll,(m-(x-i+1))/len*sum[len-1]));
}
}
return ans;
}
int main()
{
int T,cas=1;
cin>>T;
while(T--)
{
ll n,s,m,k;
scanf("%lld%lld%lld%lld",&n,&s,&m,&k);
for(int i=0;i<n;i++)scanf("%lld",&a[i]);
for(int i=0;i<n;i++)v[i]=0;
ll ans=s;
for(int i=0;i<n;i++)
{
if(v[i])continue;
p.clear();
int j=i;
while(v[j]==0) //找出循环节里的数并计算答案
{
v[j]=1;
p.push_back(a[j]);
j=(j+k)%n;
}
ans=min(ans,max(s-cal(m),0ll));
}
printf("Case #%d: %lld\n",cas++,ans);
}
return 0;
}