題解CF1389B Array Walk
阿新 • • 發佈:2022-04-04
題目連結
\(Describe\)
有\(n\)個元素的陣列,陣列的值表示得分,最初從下標為\(1\)的位置開始,總共可以向左或者向右移動\(k\)次,且向左移動的總次數不能超過\(z\)次,求恰好走\(k\)次的最大得分。
\(Solution\)
看到這題的第一思路就是\(dp\),因為每次移動只能向左右移動,所以這題是一道線性\(dp\)問題,那麼接下來的問題就是如何設定引數以及如何寫狀態轉移方程了。
我們可以發現\(n<10^5\),以及\(z\)的最大值為\(5\),於是就可以用二維\(dp\)去標記狀態,\(dp[i][j]\)表示總共移動了\(i\)次、其中向左移動了\(j\)
\(dp[i][j]=dp[i-1][j]+a[i-j*2+1]\)
\(dp[i][j]=max(dp[i][j],dp[i-1][j-1]+a[i-1-(j-1)*2])\)
當前狀態下位置的最大得分和他前一個位置有關,第一個轉移方程是往右走的情況,第二個轉移方程是往左走的情況,\(a\)陣列表示走之後到達的位置的得分,兩者取最大即為當前位置的最大得分,答案輸出即為\(dp[k][i],0\le i \le z\)中的最大值
時間複雜度\(O(n)\),常數\(z\)很小。
\(Code\)
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll t,n,k,z,a[100005],dp[100005][10]; signed main() { ios::sync_with_stdio(false); cin>>t; while(t--) { //不需要memset也不能用,用了的話複雜度為O(tn)會TLE cin>>n>>k>>z; for(ll i=1;i<=n;++i)cin>>a[i]; dp[0][0]=a[1];//初始化dp陣列 dp[1][0]=a[1]+a[2]; for(ll i=2;i<=n;++i) { for(ll j=0;j<=z;++j) { dp[i][j]=dp[i-1][j]+a[i-j*2+1]; if(j>0)dp[i][j]=max(dp[i][j],dp[i-1][j-1]+a[i-1-(j-1)*2]); } }//進行狀態轉移 ll ma=-1; for(ll i=0;i<=z;++i)ma=max(ma,dp[k][i]);//最大值即為答案 cout<<ma<<endl; } return 0; }