矩阵取数游戏 2007年NOIP全国联赛提高组(dp+高精)
矩阵取数游戏
2007年NOIP全国联赛提高组
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
题目描述 Description
【问题描述】
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均
为非负整数。游戏规则如下:
1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素值*2i,
其中i 表示第i 次取数(从1 开始编号);
4. 游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入描述 Input Description
第1行为两个用空格隔开的整数n和m。
第2~n+1 行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。
输出描述 Output Description
输出 仅包含1 行,为一个整数,即输入矩阵取数后的最大得分。
样例输入 Sample Input
2 3
1 2 3
3 4 2
样例输出 Sample Output
82
数据范围及提示 Data Size & Hint
样例解释
第 1 次:第1 行取行首元素,第2 行取行尾元素,本次得分为1*21+2*21=6
第2 次:两行均取行首元素,本次得分为2*22+3*22=20
第3 次:得分为3*23+4*23=56。总得分为6+20+56=82
【限制】
60%的数据满足:1<=n, m<=30, 答案不超过1016
100%的数据满足:1<=n, m<=80, 0<=aij<=1000
/* 高精 恶心的我啊! 终于大概差不懂几乎弄懂了封装怎么压位 就是那个高精*低精调不出来,只能写高精*高精+压位 注意输出时先输出第一个然后再setfill setw时压几位就是几 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iomanip> #define N 81 #define ll long long #define mod 10000 using namespace std; ll n,m,k,cnt,flag; ll a[N][N]; inline ll read() { ll x=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } class Big{ public: int size,num[201]; Big(){size=0;memset(num,0,sizeof num);} Big(int data) { size=0; while(data!=0){num[++size]=data%mod;data/=mod;} } inline void init(int data) { size=0; while(data!=0){num[++size]=data%mod;data/=mod;} } inline void copy(Big A) { int s1=size,s2=A.size;size=s2; for(int i=s2;i>=1;i--) num[i]=A.num[i]; } }; Big f[N][N],Pow[N]; Big ans; ostream & operator << (ostream & os,Big A) { int s=A.size; if(s==0) os<<0,flag=1; if(!flag) { os<<A.num[s]; for(int i=s-1;i;i--) os<<setfill('0')<<setw(4)<<A.num[i]; return os; } } Big operator + (Big A,Big B) { Big c; int s=max(A.size,B.size); c.size=s; for(int i=1;i<=s;i++) c.num[i]=A.num[i]+B.num[i]; for(int i=1;i<=s;i++) if(c.num[i]>=mod) { c.num[i+1]+=c.num[i]/mod; c.num[i]%=mod; } if(c.num[s+1]!=0) c.size++; return c; } Big operator * (Big A,Big B) { Big c; int s1=A.size,s2=B.size; for(int i=1;i<=s1;i++) for(int j=1;j<=s2;j++) { c.num[i+j-1]+=A.num[i]*B.num[j]; c.num[i+j]+=c.num[i+j-1]/mod; c.num[i+j-1]%=mod; } c.size=A.size+B.size; while(c.num[c.size]==0) c.size--; return c; } bool operator > (Big A,Big B) { int s1=A.size,s2=B.size; if(s1<s2) return 0; if(s1>s2) return 1; for(int i=s1;i>=1;i--) if(A.num[i]<B.num[i]) return 0; else if(A.num[i]>B.num[i]) return 1; return 0; } Big Cmax(Big A,Big B) { if(A>B) return A; else return B; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read(); memset(Pow,0,sizeof Pow); Pow[1].init(2); for(int i=2;i<=m;i++) Pow[i].copy(2*Pow[i-1]); for(int i=1;i<=n;i++) { memset(f,0,sizeof f); for(int j=1;j<=m;j++) f[j][1].copy(a[i][j]*Pow[m]); for(int k=2;k<=m;k++) for(int j=1;j<=m-k+1;j++) f[j][k].copy(Cmax(f[j][k-1]+a[i][j+k-1]*Pow[m-k+1],f[j+1][k-1]+a[i][j]*Pow[m-k+1])); ans.copy(ans+f[1][m]); } cout<<ans; return 0; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。