原题:矩阵取数游戏
题意:
对每一列,每次操作取左端或右端的数,第i次得分为所取数*2^i,求取完后的最大得分
解析:
首先是题目,本来是从外往内取,每次选左或右的最大值,乘2的当前次数次方。其实我们用dp[2][4]表示最后(4-2+1)此取2~4的最大值,从内往外取,对于以前的乘2再加上选择加的那个,第一个取的乘的2不就是2的这么多次方吗?
dp[l][r]=max(dp[l][r-1]*2+num[r],dp[l+1][r]*2+num[l]);
long long 60 points code:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define D long long
#define N 100
using namespace std;
int main(){
int t,n;scanf("%d%d",&t,&n);
D ans=0;
D dp[N][N];
while(t--){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)scanf("%lld",&dp[i][i]),dp[i][i]*=2;
for(int l=2;l<=n;l++){
for(int i=1;i<=n-l+1;i++){
dp[i][i+l-1]=max(2*dp[i][i+l-2]+dp[i+l-1][i+l-1],2*dp[i+1][i+l-1]+dp[i][i]);
}
}
ans+=dp[1][n];
}
printf("%lld\n",ans);
}
关键是数太大了,long long装不下,所以要用到>大数<
bignum 100 points code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 32
// 大数模板。。。
class BigNum
{
public:
int s[N]; //存放各位数字,s[0]为符号位,1代表正数,-1代表负数
//数组内高位存高位,123存在里面则为 1 3 2 1 ,第1个 1表示符号
int len; //长度
public:
BigNum()
{
memset(s,0,sizeof(s)); //初始化全0
s[0]=1; //默认正数
len=2; //变量初始化为0
}
void out() //输出
{
if(s[0]==-1) printf("-");
for(int i=len-1;i>0;i--)
printf("%d",s[i]);
}
void Clear()
{
memset(s,0,sizeof(s)); //初始化全0
s[0]=1; //默认正数
len=2; //变量初始化为0
}
BigNum Nizhi() //排除符号位颠倒数组
{
BigNum ans;
ans.s[0]=s[0];
for(int i=1;i<=len/2;i++)
{
ans.s[i]=s[len-i];
ans.s[len-i]=s[i];
}
ans.len=len;
return ans;
}
friend bool operator<(const BigNum &a,const BigNum &b);
friend bool operator>(const BigNum &a,const BigNum &b);
friend bool operator<=(const BigNum &a,const BigNum &b);
friend bool operator>=(const BigNum &a,const BigNum &b);
friend BigNum operator+(BigNum a,BigNum b);
friend void operator+=(BigNum &a,BigNum b);
friend BigNum operator-(BigNum a,BigNum b);
friend bool operator==(const BigNum &a,const BigNum &b);
void operator=(const int a);
};
////////////////////////////////////////////////////////////////////逻辑
bool operator<(const BigNum &a,const BigNum &b)
{
bool flag;
if(a.s[0]==-1&&b.s[0]==1) return 1; //如果a为负,b为正,那么a<b
else if(a.s[0]==1&&b.s[0]==-1) return 0; //如果a为正,b为负,那么a>b
else if(a.s[0]==1&&b.s[0]==1) flag=1; //如果a、b都为正,flag=1,表示a、b大小和符号无关
else flag=0; //如果a、b都为负,flag=0,表示a、b大小和符号有关
// flag=1 时,a、b大小和除符号外的数字大小成正比,反之反比
if(a.len>b.len) return !flag; //a的位数多,所以a大,返回0
else if(a.len<b.len) return flag; //a的位数少,所以a小,返回1
else
{
int i=a.len; //从最高位开始比
while(i-->1)
{
if(a.s[i]>b.s[i]) return !flag;
else if(a.s[i]<b.s[i]) return flag;
}
return 0; //没有差异即相等返回0
}
}
bool operator<=(const BigNum &a,const BigNum &b) //同 <
{
bool flag; // flag=1 表示两者都是正的 =0表示两者都是负的
if(a.s[0]==-1&&b.s[0]==1) return 1;
else if(a.s[0]==1&&b.s[0]==-1) return 0;
else if(a.s[0]==1&&b.s[0]==1) flag=1;
else flag=0;
// flag 表示1 ,!flag 表示0
if(a.len>b.len) return !flag;
else if(a.len<b.len) return flag;
else
{
int i=a.len;
while(i-->1)
{
if(a.s[i]>b.s[i]) return !flag;
else if(a.s[i]<b.s[i]) return flag;
}
return 1;
}
}
bool operator>(const BigNum &a,const BigNum &b)
{
return !(a<=b);
}
bool operator>=(const BigNum &a,const BigNum &b)
{
return !(a<b);
}
bool operator==(const BigNum &a,const BigNum &b)
{
if(a.s[0]==-1&&b.s[0]==1) return 0;
else if(a.s[0]==1&&b.s[0]==-1) return 0;
if(a.len>b.len) return 0;
else if(a.len<b.len) return 0;
else
{
int i=a.len;
while(i-->1)
{
if(a.s[i]>b.s[i]) return 0;
else if(a.s[i]<b.s[i]) return 0;
}
return 1;
}
}
///////////////////////////////////////////////////////运算
BigNum operator+(BigNum a,BigNum b)
{
BigNum ans;
int lm=a.len>b.len?a.len:b.len;
if(a.s[0]*b.s[0]==1) //如果两者符号位相同
{
ans.s[0]=a.s[0]; //结果符号位与任意一个相同
for(int i=1;i<lm;i++)
{
int tmp=ans.s[i]+a.s[i]+b.s[i];
if(tmp>=10)
{
ans.s[i+1]++;
}
ans.s[i]=tmp%10;
}
if(ans.s[lm]==0) ans.len=lm; //如果最高位没有进位,那么长度不变,否则加1
else ans.len=lm+1;
}
else //如果a、b符号不同,可以转化为减法
{
if(a.s[0]==1)
{
b.s[0]=1;
return a-b;
}
else
{
a.s[0]=1;
return b-a;
}
}
return ans;
}
void operator+=(BigNum &a,BigNum b)
{
a=a+b;
}
BigNum operator-(BigNum a,BigNum b)
{
BigNum ans;
if(a.s[0]==1&&b.s[0]==-1) //如果a正,b负,那么等同于a+|b|
{
b.s[0]=1;
return a+b;
}
else if(a.s[0]==-1&&b.s[0]==1) //如果a负,b正,那么等同于-(|a|+b)
{
a.s[0]=1;
ans=a+b;
ans.s[0]=-1;
return ans;
}
else if(a.s[0]==-1&&b.s[0]==-1) //如果a负,b负,那么等同于|b|-|a|
{
a.s[0]=1;
b.s[0]=1;
return b-a;
}
else //进到这一区域的,a为正,b为正
{
if(a<b) //如果a<b,那么等同于-(b-a)
{
ans=b-a;
ans.s[0]=-1;
}
else //进到这一区域a、b为正,且a>b,也就是说减出来的绝对是正数
{
int i=0;
int lm=a.len>b.len?a.len:b.len; //由于减出来必定是正数,不需要考虑lm-1位<0的情况
for(int i=1;i<lm;i++)
{
int tmp=ans.s[i]+a.s[i]-b.s[i];
if(tmp<0)
{
ans.s[i+1]--;
tmp+=10;
}
ans.s[i]=tmp;
}
while(lm>2) //清楚高位0,最多清楚到0为止
{
if(ans.s[lm-1]==0) lm--;
else break;
}
ans.len=lm;
}
}
return ans;
}
/////////////////////////////////////////赋值
void BigNum::operator=(int a)
{
Clear();
if(a<0)
{
s[0]=-1;
a=-a;
}
len=1;
while(a)
{
s[len++]=a%10;
a/=10;
}
}
BigNum dp[100][100];
int main(){
BigNum ans;
int t,n;scanf("%d%d",&t,&n);
int mid;
while(t--){
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
dp[i][j]=0;
}
}
for(int i=1;i<=n;i++)scanf("%d",&mid),dp[i][i]=mid+mid;
for(int l=2;l<=n;l++){
for(int i=1;i<=n-l+1;i++){
dp[i][i+l-1]=max(dp[i][i+l-2]+dp[i][i+l-2]+dp[i+l-1][i+l-1],dp[i+1][i+l-1]+dp[i+1][i+l-1]+dp[i][i]);
}
}
ans+=dp[1][n];
}
ans.out();printf("\n");
}