A1198. 矩阵取数游戏 dp和高精度

http://www.tsinsen.com/ViewGProblem.page?gpid=A1198

试题来源

  NOIP2007 提高组

问题描述

  帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:
  1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
  3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2i,其中i表示第i次取数(从1开始编号);
  4. 游戏结束总得分为m次取数得分之和。
  帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

输入格式

  输入包括n+1行:
  第1行为两个用空格隔开的整数nm
  第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。

输出格式

  输出包含1行,为一个整数,即输入矩阵取数后的最大得分。

样例输入

2 3
1 2 3
3 4 2

样例输出  82

样例输入

1 4
4 5 0 5

样例输出 122

样例输入

2 10
96 56 54 46 86 12 23 88 80 43
16 95 18 29 30 53 88 83 64 67

样例输出 316994

数据规模和约定

  60%的数据满足:1<=nm<=30, 答案不超过10^16
  100%的数据满足:1<=nm<=80, 0<=aij<=1000。

思路,首先进行了dp,

用f[i][j]表示区间[i, j]的最优解  f[i][j] = max(a[i] + 2 * f[i+1][j], a[j] + 2 * f[i][j-1]);//直接计算数的权值

但是后面的一直没有正确,原来是数字太大,超过了long long。

unsigned   int     0~4294967295   (10位数,4e9)

int                        -2147483648~2147483647  (10位数,2e9   2^31 - 1)   

long long:           -9223372036854775808~9223372036854775807  (19位数, 9e18 ) 2^63 - 1

unsigned long long:0~18446744073709551615  (20位数,1e19)  2^64 - 1

这里介绍_int128, 只能gcc使用。这种类型只有部分GCC编译器支持。经测试,正常运算与普通int无异,但是输入输出时无论是cin,cout还是printf都会报错,所以必须自己写输入输出函数。 
定义时与别的数据类型并没有什么区别 
eg: __int128 a,b,c; 
输入暂时采用字符串读入方式。 

#include<iostream>
#include<cstdio>
#include<set>
#include<vector>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<bits/stdc++.h>
using namespace std;
//typedef long long ll;
#define ll __int128
int m,n;
int iputs[90][90];
ll dp[90][90];
ll res;
int id;
void print(ll x) {
	if (x==0) return;
	if (x) print(x/10);
	putchar(x%10+'0');
}

void scan(ll &x) { //输入
	x = 0;
	int f = 1;
	char ch;
	if((ch = getchar()) == '-') f = -f;
	else x = x*10 + ch-'0';
	while((ch = getchar()) >= '0' && ch <= '9')
		x = x*10 + ch-'0';
	x *= f;
}

ll DP(int a,int b) {
	//cout<<a<<"---"<<b<<endl;
	if(dp[a][b]>=0)
		return dp[a][b];

	if(a==b) {
		return dp[a][b]=iputs[id][a];
	}
	ll imax1,imax2;
	imax1=DP(a+1,b);
	dp[a+1][b]=imax1;
	imax2=DP(a,b-1);
	dp[a][b-1]=imax2;
	imax1=iputs[id][a]+2*imax1;
	imax2=iputs[id][b]+2*imax2;
	if(imax1>=imax2) {
		return dp[a][b]=imax1;
	} else {
		return dp[a][b]=imax2;
	}

}
int main() {
	ll DP(int a,int b);
	void scan(ll &x);
	void print(ll x);
	cin>>n>>m;
	if(n==0||m==0) {
		cout<<0<<endl;
		return 0;
	}
	res=0;
	for(int i=0; i<n; i++) {
		for(int j=0; j<m; j++)
			cin>>(iputs[i][j]);
		memset(dp,-1,sizeof(dp));
		id=i;
		res+=2*DP(0,m-1);
	}
	if(res==0) puts("0");
	else print(res);
	return 0;
}

关于int128读写

void read(__int128 &x)
{
    x=0;
    int f=1;
    char ch;
    if((ch=getchar())=='\n') x=x;
    else if(ch=='-') f=-f;
    else x=x*10+ch-'0';
    while((ch=getchar())>='0' && ch<='9')
        x=x*10+ch-'0';
    x*=f;
}
 
void print(__int128 x)
{
    if(x<0)
    {
        x=-x;
        putchar('-');
    }
    if(x>9)
        print(x/10);
    putchar(x%10+'0');
}

另外,附加一个高精度模板 

#include <algorithm> // max
#include <cassert>   // assert
#include <cstdio>    // printf,sprintf
#include <cstring>   // strlen
#include <iostream>  // cin,cout
#include <string>    // string类
#include <vector>    // vector类
using namespace std;
 
struct BigInteger {
    typedef unsigned long long LL;
 
    static const int BASE = 100000000;
    static const int WIDTH = 8;
    vector<int> s;
 
    BigInteger& clean(){while(!s.back()&&s.size()>1)s.pop_back(); return *this;}
    BigInteger(LL num = 0) {*this = num;}
    BigInteger(string s) {*this = s;}
   BigInteger& operator = (long long num) {      							
        s.clear();
        do {
            s.push_back(num % BASE);
            num /= BASE;
        } while (num > 0);
        return *this;
    }
    BigInteger& operator = (const string& str) {
        s.clear();
        int x, len = (str.length() - 1) / WIDTH + 1;
        for (int i = 0; i < len; i++) {
            int end = str.length() - i*WIDTH;
            int start = max(0, end - WIDTH);
            sscanf(str.substr(start,end-start).c_str(), "%d", &x);
            s.push_back(x);
        }
        return (*this).clean();
    }
 
    BigInteger operator + (const BigInteger& b) const {
        BigInteger c; c.s.clear();
        for (int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = g;
            if (i < s.size()) x += s[i];
            if (i < b.s.size()) x += b.s[i];
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c;
    }
    BigInteger operator - (const BigInteger& b) const {
        assert(b <= *this); // 减数不能大于被减数
        BigInteger c; c.s.clear();
        for (int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = s[i] + g;
            if (i < b.s.size()) x -= b.s[i];
            if (x < 0) {g = -1; x += BASE;} else g = 0;
            c.s.push_back(x);
        }
        return c.clean();
    }
    BigInteger operator * (const BigInteger& b) const {
        int i, j; LL g;
        vector<LL> v(s.size()+b.s.size(), 0);
        BigInteger c; c.s.clear();
        for(i=0;i<s.size();i++) for(j=0;j<b.s.size();j++) v[i+j]+=LL(s[i])*b.s[j];
        for (i = 0, g = 0; ; i++) {
            if (g ==0 && i >= v.size()) break;
            LL x = v[i] + g;
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c.clean();
    }
    BigInteger operator / (const BigInteger& b) const {
        assert(b > 0);  // 除数必须大于0
        BigInteger c = *this;       // 商:主要是让c.s和(*this).s的vector一样大
        BigInteger m;               // 余数:初始化为0
        for (int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
			m -= b*c.s[i];
        }
        return c.clean();
    }
    BigInteger operator % (const BigInteger& b) const { //方法与除法相同
        BigInteger c = *this;
        BigInteger m;
        for (int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
            m -= b*c.s[i];
        }
        return m;
    }
    // 二分法找出满足bx<=m的最大的x
    int bsearch(const BigInteger& b, const BigInteger& m) const{
        int L = 0, R = BASE-1, x;
        while (1) {
            x = (L+R)>>1;
            if (b*x<=m) {if (b*(x+1)>m) return x; else L = x;}
            else R = x;
        }
    }
    BigInteger& operator += (const BigInteger& b) {*this = *this + b; return *this;}
    BigInteger& operator -= (const BigInteger& b) {*this = *this - b; return *this;}
    BigInteger& operator *= (const BigInteger& b) {*this = *this * b; return *this;}
    BigInteger& operator /= (const BigInteger& b) {*this = *this / b; return *this;}
    BigInteger& operator %= (const BigInteger& b) {*this = *this % b; return *this;}
 
    bool operator < (const BigInteger& b) const {
        if (s.size() != b.s.size()) return s.size() < b.s.size();
        for (int i = s.size()-1; i >= 0; i--)
            if (s[i] != b.s[i]) return s[i] < b.s[i];
        return false;
    }
    bool operator >(const BigInteger& b) const{return b < *this;}
    bool operator<=(const BigInteger& b) const{return !(b < *this);}
    bool operator>=(const BigInteger& b) const{return !(*this < b);}
    bool operator!=(const BigInteger& b) const{return b < *this || *this < b;}
    bool operator==(const BigInteger& b) const{return !(b < *this) && !(b > *this);}
};
 
 ostream& operator << (ostream& out, const BigInteger& x) {
    out << x.s.back();
    for (int i = x.s.size()-2; i >= 0; i--) {
        char buf[20];
        sprintf(buf, "%08d", x.s[i]);
        for (int j = 0; j < strlen(buf); j++) out << buf[j];
    }
    return out;
}
 
 istream& operator >> (istream& in, BigInteger& x) {
    string s;
    if (!(in >> s)) return in;
    x = s;
    return in;
}
const int maxn=105;
#define ll BigInteger  
 
int n,m;
int a[maxn];
ll dp[maxn][maxn]; 
ll ans=0;
 
 
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		
		for(int j=0;j<m;j++){
			cin>>a[j];
		}
		for(int x=0;x<m;x++){
			for(int y=0;y<m;y++){
				dp[x][y]=0;
			} 
		}
		
		ll mi=1;
		for(int j=0;j<m;j++)mi*=2;
		
		for(int j=0;j<m;j++){
			dp[j][j]=mi*a[j];
		}
		for(int len=2;len<=m;len++){	
			mi/=2;//chu2		
			for(int j=0;j<=m-len;j++){//遍历每一个大小为len的区间 
				dp[j][j+len-1]=max(dp[j+1][j+len-1]+mi*a[j],dp[j][j+len-2]+mi*a[j+len-1]);
			} 
		}
		ans+=dp[0][m-1];
	}
	
	cout<<ans<<endl;	
	return 0; 
} 

猜你喜欢

转载自blog.csdn.net/qiang_____0712/article/details/85450283
今日推荐