传送门
题意:给一个长度为n的整数序列,定义一段连续子序列的价值为这段连续子序列之和sum(L,R) — k * f(len/m),其中k为给定的整数,len为这段连续子序列的长度,f(x)表示x向上取整,其中m为给定整数,求出连续子序列的最大价值
题解:这题并不难 (虽然我手残地写崩线段树wa了一个多小时还好最后几分钟过了)首先把sum(L,R)转化成sum[R] — sum[L]的前缀和的形式,然后想到对于每个f(len/m),位置 i 作为左端点L时,R的范围在[L+f(len/m)*m,L+(f(len/m)+1)m-1],显然对于每个i作为左端点L时,应该使sum[R]尽可能大,这显然可以用线段树求最大的sum[R],而如果对于每个i作为左端点时,如果枚举f(len/m),那么复杂度就是n * n * logn 显然不可以,而考虑到距离它m的位置i+m作为左端点时的右端点R对i的贡献 sum[R] — sum[i] — k * f(len/m)相当于求max(sum[R] — sum[i] — k * f(len/m),sum[R] — sum[i+m] — k * (f(len/m) — 1),即sum[R] — k * f(len/m) — min(sum[i],sum[i+m] — k),所以可以直接用sum[i]+k更新sum[i+m],就可以把复杂度降为nlogn
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" is "<<x<<endl;
const int maxn=3e5+5;
const ll inf=2e18;
ll n,m,k,a[maxn],sum[maxn];
struct Node{
int l;
int r;
ll maxx;
}nod[maxn<<2];
void pushup(int rt){
nod[rt].maxx=max(nod[rt<<1].maxx,nod[(rt<<1)|1].maxx);
}
void build(int rt,int l,int r){
nod[rt].l=l;
nod[rt].r=r;
if(l==r){
nod[rt].maxx=sum[l];
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build((rt<<1)|1,mid+1,r);
pushup(rt);
}
ll query(int rt,int l,int r,int l0,int r0){
if(l>=l0&&r<=r0)return nod[rt].maxx;
int mid=(l+r)>>1;
ll xx=-inf;
if(mid>=l0)xx=max(query(rt<<1,l,mid,l0,r0),xx);
if(mid<r0)xx=max(query((rt<<1)|1,mid+1,r,l0,r0),xx);
return xx;
}
int main(){
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=1;i<=n;i++){scanf("%lld",&a[i]);sum[i]=sum[i-1]+a[i];}
build(1,1,n);
ll ans=0;
for(int i=1;i<=n;i++){
if(i>=m+1)sum[i-1]=min(sum[i-1],sum[i-m-1]+k);
ll x=query(1,1,n,i,min(i+m-1,n));
ans=max(ans,x-sum[i-1]-k);
}
printf("%lld\n",ans);
return 0;
}
由于m很小,也可以用n*m的dp做
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" is "<<x<<endl;
const int maxn=3e5+5;
const ll inf=2e18;
ll n,m,k,a[maxn],dp[maxn][11];
int main(){
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
ll ans=0;
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
dp[i][j]=-inf;
}
dp[i][0]=0;
}
for(int i=1;i<=n;i++){
for(int j=0;j<m;j++){
if((j-1+m)%m==0){
if(dp[i-1][(j-1+m)%m]!=-inf)dp[i][j]=max(dp[i][j],dp[i-1][(j-1+m)%m]+a[i]-k);
}
else{
if(dp[i-1][(j-1+m)%m]!=-inf)dp[i][j]=max(dp[i][j],dp[i-1][(j-1+m)%m]+a[i]);
}
ans=max(ans,dp[i][j]);
}
}
printf("%lld\n",ans);
return 0;
}