cad.net 視訊教程+塊編輯器顏色[待解決]
阿新 • • 發佈:2020-08-28
題面
前言
這題寫高精多麻煩啊,一個 __int128 就可以完全把高精替換掉,程式碼還比高精的短。
然後,我就用 __int128 水過去了。(絕對不是我懶得寫高精呢)。
題解
一句話題意 每次取數從每一行行首或行末取一個,每次取都有一定的價值,問你怎麼取價值最大。
首先,每一行可以分開來考慮,我們最後的答案就是每一行最優結果相加。
那問題就轉化為了,我們怎麼在一行取使這一行價值最大。
大家都很容易想到區間 dp吧。
狀態是 \(f[i][j]\) 表示這一行剩下從 \(i\) 到 \(j\),其他都被選上的最大價值
轉移方程 \(f[i][j] = max(f[i-1][j]+a[k][j] \times 2^{m+i-j-1} , f[i][j+1] + a[k][j] \times 2^{m+i-j-1})\)
轉移時要注意第一層是正序列舉的,但第二層卻要倒序列舉。
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; inline __int128 read() { __int128 s = 0,w = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();} return s * w; } __int128 n,m,tot,ans,w[110][110],f[110][110],base[110]; void print(__int128 x)//手寫輸入函式 { if(x>9) { print(x/10); } cout<<(int) (x%10); } int main() { n = read(); m = read(); base[0] = 1; for(int i = 1; i <= m; i++) base[i] = base[i-1] * 2;//預處理出二的冪次方 for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { w[i][j] = read(); } } for(int i = 1; i <= n; i++) { memset(f,0,sizeof(f)); tot = 0;//每做一行都要清空 for(int l = 1; l <= m; l++) { for(int r = m; r >= 1; r--)//轉移 { f[l][r] = max(f[l][r],f[l-1][r]+w[i][l-1]*base[m+l-r-1]); f[l][r] = max(f[l][r],f[l][r+1]+w[i][r+1]*base[m+l-r-1]); } } for(int j = 1; j <= m; j++) tot = max(tot,f[j][j]+w[i][j]*base[m]); ans += tot; } print(ans); return (int)0; }