https://www.luogu.com.cn/problem/P1005
以前做过的一道题,当时当贪心来做的,过不去hh,现在再看很明显的区间DP,
可以发现每一行之间是互相不影响的,所以每行进行一次DP,f[i][j]表示以区间[i,j]来做游戏能得到的最大得分,对于区间[i,j]考虑它与它的子区间的关系,因为每次只取一个数所以只用考虑两端就可以了,所以每个区间就是由两个子区间转移过来的,取i点的话就是从[i+1,j]来的,如果取j点的话就是从[i,j-1]来的,比较两个的最大值就可以了,一大坑点是结果爆ll了,所以得用高精度,想叉了以为得高精乘高精,其实只用高精乘低精就可以了
#include<iostream>
#include<vector>>
using namespace std;
typedef long long ll;
const int N=110;
int n,m,a[N][N];
vector<int> po[N],f[N][N];
vector<int> add(vector<int> A, vector<int> B)
{
if (A.size() < B.size()) return add(B, A);
vector<int> C;
int t = 0;
for (int i = 0; i < A.size(); i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
if (t) C.push_back(t);
return C;
}
vector<int> mul(vector<int> &A, int b)
{
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || t; i ++ )
{
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
return C;
}
vector<int> mx(vector<int> x,vector<int> y)
{
if(x.size()>y.size()) return x;
if(x.size()<y.size()) return y;
for(int i=x.size()-1;i>=0;i--)
if(x[i]>y[i]) return x;
else if(x[i]<y[i]) return y;
return x;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
po[0].push_back(1);
for(int i=1;i<=m;i++) po[i]=mul(po[i-1],2);//预处理2的次方
vector<int> ans;
for(int k=1;k<=n;k++)//分行处理
{
for(int len=1;len<=m;len++)//枚举长度
{
for(int i=1;i+len-1<=m;i++)
{
int l=i,r=i+len-1;//区间左右端点
f[l][r]=add(mul(po[m-len+1],a[k][l]),f[l+1][r]);
f[l][r]=mx(add(mul(po[m-len+1],a[k][r]),f[l][r-1]),f[l][r]);
}
}
ans=add(f[1][m],ans);
}
for(int i=ans.size()-1;i>=0;i--) printf("%d",ans[i]);
return 0;
}