Neko's loop(RMA+循環羣)

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

思路:

在所有的數裏面,根據他的規則就將數組分成了若干個循環圈。我們只要在每個圈裏找出任意起點能獲得的最大開心值,那麼所有的開心值取個max,最後和s比較就行啦。既然是圈那麼每跑一圈的收穫都是確定的,那麼我們就可以只計算餘數就好了。

可是有這麼一種情況,就是說我們要取得數比餘數多但又小於一個週期。爲了解決這麼一個問題,我們可以把其中一個週期放到餘數一起計算,這樣就會得到最大值啦。然後RMQ來解決最大區間子段和。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf = 1e18;
const int maxn = 1e5+666;
ll a[maxn],b[maxn],dp[maxn][20];
int mk[maxn];

void ST(ll A[],ll n) {
    for (int i = 1; i <= n; i++)
        dp[i][0] = A[i];
    for (int j = 1; (1 << j) <= n; j++) {
        for (int i = 1; i + (1 << j) - 1 <= n; i++) {
            dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
        }
    }
}
ll RMQ(int l, int r) {
    int k = (int)(log(double(r-l+1))/log((double)2));
    return max(dp[l][k], dp[r - (1 << k) + 1][k]);
}

int main()
{
    int t_t,cas = 1;
    scanf("%d",&t_t);
    while(t_t--)
    {
    	ll n,m,s,k;
    	scanf("%lld%lld%lld%lld",&n,&s,&m,&k);;
    	for(int i = 0; i < n; i++)
    	{
    		scanf("%lld",&a[i]);
    	}
    	memset(mk,0,sizeof(mk));
    	ll ans = -inf;
    	for(int i = 0; i < n; i++)
    	{
    		if(mk[i]) continue;
    		int x = i;
    		int j = 1;
    		while(!mk[x])
    		{
    			mk[x] = 1;
    			b[j++] = a[x];
    			x = (x+k)%n;
    		}
    		for(int l = 1; l < j; l++)
    		{
    			b[l+j-1] = b[l];
    			b[l+2*j-2] = b[l];
    		}
    		b[0] = 0;
    		for(int l = 1; l <= (j-1)*3; l++)
    		{
    			b[l] += b[l-1];
    		}
    		
    		ll res = 0;
    		ll M = m;
    		ll fasd = 0;
    		if(m > j-1)
    		{
    			M = m-j+1;
    			fasd = j-1;
    		}
    		else M = m;
    		ll mm = m%(j-1)+fasd;
    		ST(b,(j-1)*3LL);
    		ll mx = -inf;
    		for(int l = 1; l < j; l++)
    		{
    			ll mmx = 0;
    			ll tmp = b[j-1];
			    if(tmp > 0)
				{
				    mmx += tmp*(M/(j-1));
			    }
				ll ghf = RMQ(l,l+mm-1)-b[l-1];
			    mmx += ghf;
    			mx = max(mx,mmx);
    		}
    		ans = max(ans,mx);
    	}
    	if(ans < 0) ans = s;
    	else 
    	{
    		if(s-ans >= 0) ans = s-ans;
    		else ans = 0;
    	}
    	printf("Case #%d: %lld\n",cas++,ans);
    }
	return 0;
}

/*
10
6 10 5 2
3 -3 2 3 -4 1


*/

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章