1029 [NOIP2007]矩阵取数游戏 区间DP
链接:https://ac.nowcoder.com/acm/contest/24213/1029
来源:牛客网
题目描述
1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2.每次取走的各个元素只能是该元素所在行的行首或行尾;
3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 * 2i,其中i表示第i次取数(从1开始编号);
4.游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入描述:
第1行为两个用空格隔开的整数n和m。
第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。
输出描述:
输出一个整数,即输入矩阵取数后的最大得分。
备注:
60%的数据满足:1 ≤ n, m ≤ 30, 答案不超过1016
ij
100%的数据满足:1 ≤ n, m ≤ 80, 0 ≤ a
≤ 1000
分析
由每次从左右两端取数,经过正常思路,将取数过程反过来,就可以用小区间推出大区间的思路求出这道题,可知这题是区间DP
当时写出来过不了看了题解,发现题解写区间DP 的方式很优秀,做个记录
for(int k = 1;k<=m;k++) { for(int i = 1,j = k;j<=m;i++,j++) { 区间dp状态转移 } }
//-------------------------代码----------------------------
#define LL __int128
#define int LL
const int N = 200;
int n,m;
int a[N][N];
int dp[N][N][N];
LL read() {
LL x = 0,f = 1;
char ch = getchar();
while(ch<'0' || ch > '9'){if(ch =='-')f = -1;ch = getchar();}
while(ch>='0' && ch<='9'){x = x * 10 + ch - '0';ch =getchar();}
return x * f;
}
void print(LL x) {
if( x< 0) { putchar('-');x = -x;}
if( x /10) print(x / 10);
putchar(x % 10 + '0');
}
int qmi(int a,int b) {
int res = 1;
while(b) {
if(b & 1) res = res * a;
b >>= 1;
a = a * a;
}
return res;
}
void solve()
{
n= read(),m = read();
fo(i,1,n) {
fo(j,1,m) {
a[i][j] = read();
}
}
for(int i = 1;i<=n;i++) {
for(int k = 1;k<=m;k++) {
for(int l = 1,r = k;l<=m;r ++ ,l++) {
dp[i][l][r] = max(dp[i][l+1][r] + (LL)a[i][l] * qmi(2,(m-k+1)),dp[i][l][r-1] + a[i][r] * qmi(2,(m-k+1)));
}
}
}
int res = 0;
for(int i = 1;i<=n;i++) {
res += dp[i][1][m];
}
print(res);
}
signed main(){
clapping();TLE;
// int t;cin>>t;while(t -- )
solve();
// {solve(); }
return 0;
}
/*样例区
*/
//------------------------------------------------------------