codeforces1197D Yet Another Subarray Problem dp
网址:http://codeforces.com/problemset/problem/1197/D
题意:
给出长度为$n$的序列和$m$,$k$($n \leq 3e5,m \leq 10,k \leq 1e9$),求$\sum_{i=l}^{r}a_i-k \lceil \frac {r-l+1}{m} \rceil$的最大值。
题解:
第一眼下去感觉是最大子列和,然后直接WA at t3和t8。感觉没问题,后面想想其实不行,因为减去的区间长度是随着子列的长度变化的,就算记录了选取的区间长度进行在线处理。没有丢掉的一段在减去对应的值之后也可能小于丢掉的。所以这个题只能对每一个数枚举其位置,即$j%m==i?(i \in [0,m-1])$,然后让右端点处(满足$j%m==i$)的值减去一个$k$,构成新序列,在新序列上求最大子列和。求解时一定要在到达右端点时才更新最大值,否则会漏减一个$k$。为什么需要这么做?答案一定是出现在某次枚举的右端点,这样子枚举可以在不需要分类讨论就减去相应个数的k,否则有可能出现区间长度大于一个$m$的区间只减去了一个$k$的错误结果。
AC代码:
#include <bits/stdc++.h> using namespace std; long long a[300005],b[300005]; int main() { int n,m,k; cin>>n>>m>>k; for(int i=0;i<n;++i) cin>>a[i]; long long maxx=0,ans=0; for(int i=0;i<m;++i)//枚举减k的位置 { for(int j=0;j<n;++j) b[j]=a[j]-(j%m==i?k:0);//对需要减k的地方处理 maxx=0; for(int j=0;j<n;++j) { maxx=max(maxx+b[j],0ll);//求最大子列和 if(j%m==i) ans=max(ans,maxx);//保证了所有的最大子列和都减了相应个数的k cout<<maxx<<" "; } cout<<endl; } cout<<ans<<endl; return 0; }