1. 程式人生 > 實用技巧 >cad.net 視訊教程+塊編輯器顏色[待解決]

cad.net 視訊教程+塊編輯器顏色[待解決]

題面

click

前言

這題寫高精多麻煩啊,一個 __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;
}