链接:https://www.luogu.org/problemnew/show/P1005
题意:有一个n*m的矩阵。有m次取数操作,每次取数时,每行都要取出左边第一个或者右边第一个,有一个权值Vi等于取出的数*,i为第几次取数。求总权值最大。
思路:行与行之间没有相互影响,可以看作是独立的。对于一行,取左右两个端点l,r。dp[l][r]=max(dp[l-1][r]+num[][l-1]*,dp[l][r+1]+num[][r+1]*
),这样的话,dp的终点是l=r的地方,枚举一下dp[x][x]+num[][x]*
,(x
[1,m]),最大值就是该行的最大贡献,加到答案中。n<=80,显然超过了long long范围,需要用高精度
Java参考代码:
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static BigInteger Max(BigInteger a, BigInteger b){
if(a.compareTo(b) >= 0)return a;
else return b;
}
public static void main(String[] args){
BigInteger [] er = new BigInteger[81];
BigInteger tmp = new BigInteger("1");
for (int i = 1; i <= 80; i++){
tmp = tmp.multiply(new BigInteger("2"));
er[i] = tmp;
}
tmp = new BigInteger("0");
BigInteger [][] dp = new BigInteger[82][82];
BigInteger [][] num = new BigInteger[82][82];
Scanner cin = new Scanner(System.in);
int n, m;
n = cin.nextInt();
m = cin.nextInt();
for (int i = 1; i <= n; i++){
for (int j = 1;j <= m; j++){
num[i][j] = cin.nextBigInteger();
}
}
for (int i = 1; i <= n; i++)num[i][0] = num[i][m+1] = tmp;
int cnt = 0;
BigInteger ans = new BigInteger("0");
BigInteger tp = new BigInteger("0");
for (int i = 1; i <= n; i++){
for (int j = 0; j <= m; j++){
for (int k = 0; k <= m+1; k++){
dp[j][k] = tmp;
}
}
for (int j = 1; j <= m; j++){
for (int k = m; k >= j; k--){
cnt = j - 1 + m - k;
if(cnt == 0)continue;
dp[j][k] = Max(dp[j-1][k].add(num[i][j-1].multiply(er[cnt])),dp[j][k+1].add(num[i][k+1].multiply(er[cnt])));
}
}
tp = new BigInteger("0");
for (int j = 1; j <= m; j++){
tp = Max(tp, dp[j][j].add(num[i][j].multiply(er[m])));
}
ans = ans.add(tp);
}
System.out.println(ans);
}
}