洛谷 P1005 动态规划 大数 区间dp
Problem Description
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n×m的矩阵,矩阵中的每个元素a(i,j)均为非负整数。游戏规则如下:
1 每次取数时须从每行各取走一个元素,共n个。经过m次后取完矩阵内所有元素;
2 每次取走的各个元素只能是该元素所在行的行首或行尾;
3 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值×2^i,其中i表示第i次取数(从1开始编号);
4 游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
Input
输入文件包括n+1行:
第1行为两个用空格隔开的整数n和m。
第2∽n+1行为n×m矩阵,其中每行有m个用单个空格隔开的非负整数。
Output
输出文件仅包含1行,为一个整数,即输入矩阵取数后的最大得分。
Sample Input
2 3
1 2 3
3 4 2
Sample Output
82
Analysis of ideas
设k=m-(R-L),可以得到状态转移方程:f[L][R]=max(num[L]*p[k]+dp(L+1,R),dp(L,R-1)+num[R]*p[k])
for(int len=0;len<=m;++len)
for(int i=1;i+len<=m;++i)
f[i][i+len]=max(2*f[i+1][i+len]+2*a[i],2*f[i][i+len-1]+2*a[i+len]);
Accepted code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <vector>
#include <queue>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define cin(a) scanf("%d",&a)
#define pii pair<int,int>
#define ll long long
#define gcd __gcd
const int inf = 0x3f3f3f3f;
const int maxn = 200100;
int n,m,k,t;
__int128 a[100][100];
__int128 dp[100][100];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline void print(__int128 x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
void init()
{
for(int i = 0; i < m; i++)
{
for(int j = 0; j < m; j++)
{
dp[i][j] = 0;
}
}
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
cin(n),cin(m);
for(int i = 0 ; i < n; i++)
{
for(int j = 0; j < m; j++)
{
a[i][j] = read();
}
}
__int128 ans = 0;
for(int i = 0; i < n; i++)
{
init();
for(int len = 0; len < m; len++) //区间长度
{
for(int k = 0; k+len < m; k++) //左边界l
{
dp[k][k+len] = max(2*dp[k+1][k+len]+2*a[i][k], 2*dp[k][k+len-1]+2*a[i][k+len]); //有点东西
}
}
ans += dp[0][m-1];
}
print(ans);
return 0;
}

浙公网安备 33010602011771号