題目描述
帥帥經(jīng)常跟同學玩一個矩陣取數(shù)游戲:對于一個給定的n*m的矩陣,矩陣中的每個元素aij均為非負整數(shù)。游戲規(guī)則如下:
1.每次取數(shù)時須從每行各取走一個元素,共n個。m次后取完矩陣所有元素;
2.每次取走的各個元素只能是該元素所在行的行首或行尾;
3.每次取數(shù)都有一個得分值,為每行取數(shù)的得分之和,每行取數(shù)的得分 = 被取走的元素值*2^i,其中i表示第i次取數(shù)(從1開始編號);
4.游戲結(jié)束總得分為m次取數(shù)得分之和。
帥帥想請你幫忙寫一個程序,對于任意矩陣,可以求出取數(shù)后的最大得分。
輸入輸出格式
輸入格式:
輸入文件game.in包括n+1行:
第1行為兩個用空格隔開的整數(shù)n和m。
第2~n+1行為n*m矩陣,其中每行有m個用單個空格隔開的非負整數(shù)。
數(shù)據(jù)范圍:
60%的數(shù)據(jù)滿足:1<=n, m<=30,答案不超過10^16
100%的數(shù)據(jù)滿足:1<=n, m<=80,0<=aij<=1000
輸出格式:
輸出文件game.out僅包含1行,為一個整數(shù),即輸入矩陣取數(shù)后的最大得分。
輸入輸出樣例
輸入樣例#1:
2 3
1 2 3
3 4 2
輸出樣例#1:
82
一道明顯的DP題,但是卻考察了高精度計算,因為M最大可以是80,2的80次方明顯爆出銀河系了...由于本人特別懶,而且對高精并無自信,所以只寫了long long的60分代碼.
下面來說說DP的思路
首先很明顯的一件事情是你可以一行一行的做DP,最后取極大值相加得到最終結(jié)果。問題是這個狀態(tài)怎么定義最合適,一開始我想的是取某個區(qū)間能得到的最大狀態(tài)是什么,但是這里有個問題,狀態(tài)怎么轉(zhuǎn)移?你無法知道區(qū)間中誰是被最后取走的,而這對于解題十分關(guān)鍵。如果你不知道是誰被最后取,那你只能枚舉,而這個過程不是很好處理,反正我失敗了。最后研究題解發(fā)現(xiàn)狀態(tài)可以定義為,取 i,j為剩余段的最大收益,顯然最終狀態(tài)應該是 f[i][i]+a[i]^M,這樣的好處在于狀態(tài)轉(zhuǎn)移方便了,很明顯你只可以從 f[i-1][j]或者f[i][j+1]轉(zhuǎn)移過來,因為一個剩余線段一定是從另外兩種不同的更長剩余線段走來的,過程就是被拿走了一個,加上它的值就是新解.
以下是代碼。(待我哪天寫個高精版本填坑)
include <iostream>
#include <cmath>
#include <cstring>
#define SIZE 100+10
using namespace std;
int N, M;
string a[105][105];
string f[105][105][105];
/*string jia(string s1, string s2) {
int a[SIZE], b[SIZE], c[SIZE];
int size_a = s1.size(), size_b = s2.size();
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(c, 0, sizeof(c));
for (int i = 0; i < size_a; i++) a[size_a - i] = s1[i] - '0';
for (int i = 0; i < size_b; i++) b[size_b - i] = s2[i] - '0';
int size_c = 1, x = 0;
while (size_c <= size_a || size_c <= size_b) {
c[size_c] = a[size_c] + b[size_c] + x;
x = c[size_c] / 10;
c[size_c] %= 10;
size_c++;
}
c[size_c] = x;
while (size_c > 1 && c[size_c] == 0) size_c--;
string res;
res.resize(size_c);
for (int i = size_c; i >= 1; i--) res[size_c - i] = c[i] + '0';
return res;
}*/
string cheng(string s1, string s2) {
int a[SIZE], b[SIZE], c[SIZE];
int size_a = s1.size(), size_b = s2.size();
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(c, 0, sizeof(c));
for (int i = 0; i < size_a; i++) a[size_a - i] = s1[i] - '0';
for (int i = 0; i < size_b; i++) b[size_b - i] = s2[i] - '0';
for (int i = 1; i <= size_a; i++) {
int x = 0;
for (int j = 1; j <= size_b; j++) {
int now = i + j - 1;
c[now] += a[i] * b[j] + x;
x = c[now] / 10;
c[now] %= 10;
}
c[i + size_b] = x;
}
int size_c = size_a + size_b;
while (size_c > 1 && c[size_c] == 0) size_c--;
string res;
res.resize(size_c);
for (int i = size_c; i >= 1; i--) res[size_c - i] = c[i] + '0';
return res;
}
string jia(string s1, string s2)
{
int len=max(s1.length(),s2.length());
int a[50],b[50];
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<s1.length();i++)
a[s1.length()-1-i]=s1[i]-'0';
for(int i=0;i<s2.length();i++)
b[s2.length()-1-i]=s2[i]-'0';
string ret;
int ans[50];
memset(ans,0,sizeof(ans));
for(int i=0;i<=50;i++)
ans[i]=0;
int x=0;
// cout<<a[len-1];
for(int i=0;i<len;i++)
{
ans[i]=a[i]+b[i]+x;
// cout<<ans[i]<<' '<<x<<'\n';
x=ans[i]/10;
ans[i]%=10;
}
ans[len]=x;
if(ans[len])
{
len++;
}
ret.resize(len);
for(int i=0;i<len;i++)
{
// cout<<ans[i];
ret[len-1-i]=ans[i]+'0';
}
// cout<<'\n';
return ret;
}
/*string cheng(string s1, string s2)
{
int a[50], b[50],c[50];
for(int i=0;i<=50;i++)
{
a[i]=0;
b[i]=0;
c[i]=0;
}
for(int i=0;i<s1.length();i++)
a[s1.length()-i-1]=s1[i]-'0';
for(int i=0;i<s2.length();i++)
b[s2.length()-i-1]=s2[i]-'0';
for(int i=0;i<s1.length();i++)
{
int x=0;
for(int j=0;j<s2.length();j++)
{
int now=i+j;
c[now]+=a[i]*b[j]+x;
x=c[now]/10;
c[now]%=10;
}
c[i+s2.length()]=x;
}
int len=0;
while(c[len]!=0)
{
len++;
}
string ret;
ret.resize(len);
for(int i=0;i<len;i++)
{
ret[len-i-1]=c[i]+'0';
}
// cout<<ret.size()<<'\n';
return ret;
}*/
/*string maxs(string s1,string s2)
{
int i;
if(s1.size()>s2.size())
return s1;
if(s2.size()>s1.size())
return s2;
for(i=0;i<s1.length();i++)
{
if(s1[i]>s2[i])
return s1;
if(s2[i]>s1[i])
return s2;
}
return s1;
}*/
inline string maxs(string a, string b) {
if (a.size() > b.size()) return a;
if (a.size() < b.size()) return b;
for (int i = 0; i < a.size(); i++) {
if (a[i] > b[i]) return a;
if (a[i] < b[i]) return b;
}
return a;
}
string paw[1005];
int main()
{
int i, j, k;
cin>>N>>M;
// cout<<jia("12345",cheng("123","7"));
paw[0]="1";
for(i=1;i<=M;i++)
{
paw[i]=cheng("2",paw[i-1]);
}
for(i=1;i<=N;i++)
{
for(j=1;j<=M;j++)
cin>>a[i][j];
}
for(i=1;i<=N;i++)
{
for(j=1;j<=M;j++)
{
f[i][j][j]=cheng(a[i][j],paw[M]);
}
}
for(i=1;i<=N;i++)
{
for(j=M-1;j>=1;j--)
{
for(k=1;k+j-1<=M;k++)
{
if(k+j-1==k)
{
f[i][k][k+j-1]=jia(f[i][k][k+j-1],maxs(jia(f[i][k-1][k+j-1],cheng(a[i][k-1],paw[M-j])),jia(f[i][k][k+j],cheng(a[i][k+j],paw[M-j]))));
}
else
{
f[i][k][k+j-1]=maxs(jia(f[i][k-1][k+j-1],cheng(a[i][k-1],paw[M-j])),jia(f[i][k][k+j],cheng(a[i][k+j],paw[M-j])));
// cout<<f[i][k][k+j-1]<<' '<<k<<' '<<k+j-1<<'\n';
}
//f[i][k][k+j-1]=maxs(f[i][k-1][k+j-1]+a[i][k-1]*power(2,M-j),f[i][k][k+j]+a[i][k+j]*power(2,M-j));
}
}
}
string ans;
for(i=1;i<=N;i++)
{
string tmp="0";
for(j=1;j<=M;j++)
{
tmp=maxs(tmp,f[i][j][j]);
}
ans=jia(ans,tmp);
}
cout<<ans<<'\n';
}