题意:
给出一个n*m的矩阵,每一次取数从每一行中取一个数,每行取数的得分为每行所取数a[i][j] * ,k表示第几次取,且每次取数只能取头或者尾。求取完后的得分最大值?
思路:
我们可以发现每一行的取数只与当前行有关,所以该题相当于求n次数组中取数得分之和。
我们可以区间dp解决。每一次不断增加区间长度,区间长度为1时相当于该数为最后一个取得。
状态转化方程:
dp[i][j]=max(dp[i+1][j]+(a[i]<<(j-i+1),dp[i][j-1]+(a[j]<<(j-i+1)));
结果将每一行的dp[1][m]加起来就好。
注意:对于数据范围最好用__int128,否则只能用高精度了。
代码:
#include <bits/stdc++.h>
#define inf 99824435300000
using namespace std;
typedef long long ll;
inline __int128 read()
{
__int128 x=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
{
f=-f;
}
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return f*x;
}
inline void write(__int128 x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
struct w
{
ll x, y;
} w, w2;
__int128 a[105], dp[105][105], sum=0;
int main()
{
int n, m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
memset(dp,0,sizeof(dp));
for(int j=1;j<=m;j++)
{
a[j]=read();
dp[j][j]=a[j]<<m;
}
for(int k=2;k<=m;k++)
{
for(int j=1;j+k-1<=m;j++)
{
dp[j][j+k-1]=max(dp[j][j+k-2]+(a[j+k-1]<<(m-k+1)),dp[j+1][j+k-1]+(a[j]<<(m-k+1)));
}
}
sum+=dp[1][m];
}
write(sum);
return 0;
}

京公网安备 11010502036488号