洛谷P1005 矩阵取数游戏

传送门

Solution:

首先发现每一行都是独立的。
发现可以dp,设 f [ i ] [ j ] f[i][j] f[i][j] i i i j j j的最大分数。决策有两种,当前取 i i i或当前取 j j j
显然要加高精。
具体细节见代码。

code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const int MAXN = 107;
int N, M;
struct BIGNUM {
	int s[MAXN], len;
	BIGNUM () {memset(s, 0, sizeof(s)); len = 0;}
	BIGNUM operator = (const char *c) {
		len = strlen(c);
		for(int i = 0; i < len; i++)
			s[i] = c[len - i - 1] - '0';
		return *this;
	}
	BIGNUM operator = (const int x) {
		char c[MAXN];
		sprintf(c, "%d", x);
		*this = c;
		return *this;
	}
	BIGNUM operator + (const BIGNUM x) {
		BIGNUM c;
		c.len = max(len, x.len) + 1;
		for(int i = 0; i < c.len; i++) {
			c.s[i] += s[i] + x.s[i];
			c.s[i + 1] += c.s[i] / 10;
			c.s[i] %= 10;
		}
		while(!c.s[c.len - 1] && c.len > 0) c.len--;
		return c;
	}
	BIGNUM operator * (const BIGNUM x) {
		BIGNUM c;
		c.len = len + x.len + 1;
		for(int i = 0; i < len; i++)
			for(int j = 0; j < x.len; j++) {
				c.s[i + j] += s[i] * x.s[j];
				c.s[i + j + 1] += c.s[i + j] / 10; 
				c.s[i + j] %= 10;
			}
		while(!c.s[c.len - 1] && c.len > 0) c.len--;
		return c;
	}
	bool operator < (const BIGNUM x) {
		if(len != x.len) return len < x.len;
		for(int i = len - 1; i >= 0; i--)
			if(s[i] != x.s[i])
				return s[i] < x.s[i];
		return false;
	}
	BIGNUM (const char *c) {*this = c;}
	BIGNUM (const int x) {*this = x;}
};
istream& operator >> (istream& in, BIGNUM &x) {
	char c[MAXN];
	scanf("%s", c);
	x = c;
	return in;
}
ostream& operator << (ostream &out, BIGNUM x) {
    if(x.len == 0) printf("0");
	for(int i = x.len - 1; i >= 0; i--)
		printf("%d", x.s[i]);
	return out;
}
BIGNUM a[MAXN][MAXN];
BIGNUM f[MAXN][MAXN];
BIGNUM powe[MAXN];

void dp(int lin) {
	memset(f, 0LL, sizeof(f));
	powe[0].len = 1; powe[0].s[0] = 1;
	BIGNUM sth;
	sth.len = 1, sth.s[0] = 2;
	for(int i = 1; i <= 100; i++) powe[i] = powe[i - 1] * sth;
	for(int i = 1; i <= M; i++) f[i][i] = a[lin][i] * powe[M];
	
	for(int k = 2; k <= M; k++)
		for(int i = 1; i + k - 1 <= M; i++) {
			int j = i + k - 1;
			BIGNUM x = f[i + 1][j] + (a[lin][i] * powe[M - k + 1]),
				y = f[i][j - 1] + (a[lin][j] * powe[M - k + 1]);
			if(x < y)
				f[i][j] = y;
			else 
				f[i][j] = x;
		}
}
int main() {
	#ifdef test
		freopen("test.txt", "r", stdin);
	#endif
	cin >> N >> M;
	for(int i = 1; i <= N; i++)
		for(int j = 1; j <= M; j++)
			cin >> a[i][j];
	BIGNUM ans;
	for(int lin = 1; lin <= N; lin++) {
		dp(lin); ans = ans + f[1][M];
	}
	cout << ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值