题意就是给出n个数,在n个数上每次跳k个数,最多可以跳m次,你可以选择跳任意次,也可以都不跳,问你为了达到目标了快乐值至少在开始的需要多少快乐值。
题目可以转换成找出循环节,然后再循环节上疯狂试探我可以得到的最大快乐值,然后减一下。
刚开始想着找循环节,只找了一个,用栈存,然后发现可能会有多个循环节,需要考虑多个循环节的最大值,就转成vector存了。
对于每一个循环节,先找一次长度为m的序列,但是m可能比我的循环节来的大,所以我考虑循环起来。让 y 表示的我循环起来的圈数,y = m / len, x表示剩余的还没走的数,x = m % len,如果一圈可以获得的最大值,我就可以直接加上它,一开始我y圈的快乐值算成了y*sum,然后再去求最后x步的最大快乐值,然后相加,最后错了...炜神给了样例
1
5 1000 30 2
-1 -2 -3 -4 15
这时候我可以循环六圈,但是答案却不是这么算的,因为题目说我可以在任何时候停止,所以我可以在从15开始,到第五圈的15的时候提前结束,这样最后的负数我可以不取到,
所以这时候能直接计算出的最大值只有前y-1圈,然后特判能否循环起来,如果至少可以循环一圈的话,把 x = x + len,对于最后一圈进行特判,求出最后一圈加上剩余一点点步数可以得到的最大的快乐值。然后在相加。
这时候我最后一步的范围就是(0, 2*len),所以能走到的最大范围是(len-1,3*len),所以在求最大连续子串和的时候前缀和的数量应该开三倍空间。然后这题用deque会wa,可能是爆了吧...
#include<map> #include<set> #include<ctime> #include<cmath> #include<stack> #include<queue> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define lowbit(x) (x & (-x)) #define INOPEM freopen("in.txt", "r", stdin) #define OUTOPEN freopen("out.txt", "w", stdout) typedef unsigned long long int ull; typedef long long int ll; const double pi = 4.0*atan(1.0); const int inf = 0x3f3f3f3f; const ll INF = 1e18+100; const int maxn = 1e5; const int maxm = 1e9+10; const int mod = 1e9+7; using namespace std; ll n, m; int T, tol; ll s, k; bool vis[maxn]; ll a[maxn]; ll b[maxn]; ll sum[maxn]; vector<ll> vec[maxn]; struct Node { int first; ll second; }; Node q[maxn]; void init() { tol = 0; memset(q, 0, sizeof q); for(int i=0; i<maxn; i++) vec[i].clear(); memset(vis, 0, sizeof vis); } ll solve(int op, int n, ll m) { ll ans = 0; memset(sum, 0, sizeof sum); for(int i=0; i<n; i++) sum[i] = i==0 ? vec[op][i] : sum[i-1] + vec[op][i]; for(int i=n; i<2*n; i++) sum[i] = sum[i-1] + vec[op][i-n]; for(int i=2*n; i<3*n; i++) sum[i] = sum[i-1] + vec[op][i-2*n]; // for(int i=0; i<3*n; i++) printf("%lld%c", sum[i], i==3*n-1 ? ' ' : ' '); int head = 0; int tail = 0; for(int i=0; i<3*n; i++) { while(head < tail && q[tail-1].second > sum[i-1]) tail--; while(head < tail && q[head].first + m < i) head++; q[tail].first = i-1; q[tail].second = sum[i-1]; tail++; if(ans < sum[i] - q[head].second) { ans = sum[i] - q[head].second; } } return ans; } int main() { int cas = 1; scanf("%d", &T); while(T--) { init(); 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++) { if(!vis[i]) { int pos = i; while(!vis[pos]) { vis[pos] = 1; vec[tol].push_back(a[pos]); pos = (pos + k) % n; } tol++; } } // for(int i=0; i<tol; i++) for(int j=0; j<vec[i].size(); j++) printf("%lld%c", vec[i][j], j==vec[i].size()-1 ? ' ' : ' '); ll ans = -inf; for(int i=0; i<tol; i++) { ll res = -inf; int len = vec[i].size(); ll tmp = 0; for(int j=0; j<len; j++) tmp += vec[i][j]; res = solve(i, len, m); ans = max(ans, res); if(tmp < 0) continue; ll x = m % len; ll y = m / len; tmp = max(y-1, 0ll) * tmp; if(y >= 1) x += len; res = max(res, solve(i, len, x) + tmp); ans = max(ans, res); } ans = max(0ll, s-ans); printf("Case #%d: %lld ", cas++, ans); } return 0; }