質問https://codeforces.com/gym/297792/problem/D
質問の意味:サブシーケンス[l、r]のコストを指定して
、この配列の最大コストを見つけます。
元のアイデア:最初に使用された方法は、ノードのストレージ間隔を定義し、長さlの各間隔の最大合計、および対応する左右のエンドポイントを見つけて、それらをadd配列に保存することです。ルーラーメソッドで各add [i]を更新します。最後に、addで各長さのコストを計算し、最大値を取得します。
このような考え方は正しいですが、残念ながら定規の時間コストが大きすぎて、直接タイムアウトします。
エラーコードは次のとおりです。
#include <bits/stdc++.h>
#include <algorithm>
#include<iostream>
#include <stdio.h>
#define INF 0x3f3f3f3f
const int maxn=300005;
using namespace std;
typedef long long ll;
ll a[maxn];
ll pre[maxn];
//int vis[maxn];
struct node{
ll l,r;
ll sum;
}add[maxn];
int main(){
ll n,m,k;
cin>>n>>m>>k;
pre[0]=0;
a[0]=0;
for(ll i=1;i<=n;i++){
cin>>a[i];
pre[i]=pre[i-1]+a[i];
}
add[n].sum=pre[n];
add[n].l=1;
add[n].r=n;
for(ll i=n-1;i>=1;i--){
ll left=1;
ll right=left+i-1;
ll sum=pre[right];
add[i].sum=sum;
while(right<=n){
sum-=a[left];
left++;
right++;
sum+=a[right];
add[i].sum=max(add[i].sum,sum);
}
}
ll sum=0;
ll ans=0;
for(ll i=1;i<=n;i++){
ll cushu=(i-1)/m+1;
sum=add[i].sum-k*cushu;
ans=max(sum,ans);
}
cout<<ans<<endl;
return 0;
}
次に、解を調べたところ、これは実際にはバックパックdpであるdpで実行できることがわかりました。dp[i] [j]を使用して、iを右の境界dp [i]として連続するjの最大値を表します。 [j] = dp [i -1] [j-1]、jが0の場合、これは新しいm長セグメント(開始)、または前のm長セグメントからkを引いたものと同等であるためj = = 0、dp [i] [j] = max(a [i] -k、dp [i-1] [m-1] + a [i] -k);最終的な答えは、すべてのdpの最大値です。値。
コード:
#include <bits/stdc++.h>
#include <algorithm>
#include<iostream>
#include <stdio.h>
#define INF 0x3f3f3f3f
const int maxn=300005;
using namespace std;
typedef long long ll;
ll a[maxn];
ll dp[maxn][20];
int main(){
ll n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
ll ans=0;
for(ll i=1;i<=n;i++){
for(ll j=0;j<min(i,m);j++){
if(j==0)
dp[i][j]=max(a[i]-k,dp[i-1][m-1]+a[i]-k);
else
dp[i][j]=dp[i-1][j-1]+a[i];
ans=max(ans,dp[i][j]);
}
}
cout<<ans<<endl;
return 0;
}