《地心護核者》裝備屬性及獲取方法介紹
阿新 • • 發佈:2022-03-17
P1005 [NOIP2007 提高組] 矩陣取數遊戲
貪心?假了。
1 4
4 5 0 5
這組樣例應該是 \(5 \times 2 + 0\times 4+ 4 \times 8 + 5 \times 16 = 122\)
你的貪心呢?\(4 \times 2 + 5 \times 4 + 0 \times 8 + 5 \times 16 = 108\)
你還覺得貪心對嗎?
正解是區間DP,那怎麼做?
我們考慮,每一行之間取數互不影響,所以可以一行一行 DP 進行加和。
這個轉移其實也比較好想,因為只能從兩頭取得分,所以我們設 \(f[l][r]\) 為區間 \([l,r]\) 的最大得分:
\[f[l][r]=max(f[l+1][r]+a[l],f[l][r-1]+a[r]) \times 2 \]為什麼 \(\times 2\)
這題要求寫高精,但是我不會,所以用 __int128 水
/* Knowledge : Rubbish Algorithm Work by :Gym_nastics Time : O(AC) */ #include<bits/stdc++.h> #define int __int128 using namespace std; const int N=100; int read() { int x=0,f=0;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) f|=(ch=='-'); for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch&15); return f?-x:x; } void print(int x) { if(x<0) putchar('-'),x=-x; if(x>9) print(x/10); putchar(x%10+48); } int Ans,n,m,f[N][N]; int calc(int *s){ memset(f,0,sizeof f); for(int len=1;len<=m;len++){ for(int l=1;l+len-1<=m;l++){ int r=l+len-1; f[l][r]=max(f[l+1][r]+s[l],f[l][r-1]+s[r])*2; } }return f[1][m]; } int a[N][N]; signed main() { n=read();m=read(); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) a[i][j]=read(); for(int i=1;i<=n;i++) Ans+=calc(a[i]); return print(Ans),0; }