题目链接:传送门
题目大意:
给定长度为m的数列aj,每次从两端取一个数,得到2k * aj的价值(k为当前的次数,从1开始到m),总共有n行这样的数列,求最大价值总和。
1 ≤ n, m ≤ 80, 0 ≤ aj ≤ 1000;
思路:
状态f[i][j]表示取剩下ai,ai+1,…,aj时的最大价值。
起始状态:
f[0][m-1] = 0;
转移方程:
f[i][j-1] = max(f[i][j-1], f[i][j] + 取掉aj得到的价值);
f[i+1][j] = max(f[i+1][j], f[i][j] + 取掉ai得到的价值);
PS:吃灰模板居然出了bug,还因此WA了一发,是时候更新一下高精模板了。
#include <bits/stdc++.h> using namespace std; const int maxn = 35; const int MAX_N = 80 + 5; struct bigInt{ int len, d[maxn]; void clean() { while(len > 1 && !d[len-1]) len--; } string str() const { string s; for (int i = 0; i < len; i++) s += d[len-1-i] + '0'; return s; } bigInt() { memset(d, 0, sizeof d); len = 1; } bigInt(int num) { *this = num; } bigInt(char* num) { *this = num; } bool operator < (const bigInt& b) const { if(len != b.len) return len < b.len; for (int i = len-1; i >= 0; i--) if (d[i] != b.d[i]) return d[i] < b.d[i]; return false; } bool operator >(const bigInt& b) const{return b < *this;} bool operator<=(const bigInt& b) const{return !(b < *this);} bool operator>=(const bigInt& b) const{return !(*this < b);} bool operator!=(const bigInt& b) const{return b < *this || *this < b;} bool operator==(const bigInt& b) const{return !(b < *this) && !(b > *this);} bigInt operator = (const char* num) { memset(d, 0, sizeof d); len = strlen(num); for (int i = 0; i < len; i++) d[i] = num[len-1-i] - '0'; clean(); return *this; } bigInt operator = (int num) { char s[20]; sprintf(s, "%d", num); *this = s; return *this; } bigInt operator + (const bigInt& b) { bigInt c = *this; for (int i = 0; i < b.len; i++) { c.d[i] += b.d[i]; c.d[i+1] += c.d[i]/10; c.d[i] %= 10; } c.len = max(len, b.len)+1; c.clean(); return c; } bigInt operator - (const bigInt& b) { bigInt c = *this; int i; for (i = 0; i < b.len; i++) { c.d[i] -= b.d[i]; if (c.d[i] < 0) c.d[i] += 10, c.d[i+1]--; } while (c.d[i] < 0) c.d[i++] += 10, c.d[i]--; c.clean(); return c; }//只能正数大减小 bigInt operator * (const bigInt& b) const { bigInt c; for (int i = 0; i < len; i++) for (int j = 0; j < b.len; j++) c.d[i+j] += d[i] * b.d[j]; for (int i = 0; i < len+b.len || !c.d[i]; c.len = ++i) { c.d[i+1] += c.d[i] / 10; c.d[i] %= 10; } c.clean(); return c; } bigInt operator / (const bigInt& b) { bigInt c = *this, res = 0; for (int i = 0; i < len; i++) { res = res*10 + c.d[len-1-i]; int j; for (j = 0; j < 10; j++) if(res < b*(j+1)) break; c.d[len-1-i] = j; res = res - b*j; } c.clean(); return c; } bigInt operator % (const bigInt& b) { bigInt res = 0; for (int i = 0; i < len; i++) { res = res*10 + d[len-1-i]; int j; for (j = 0; j < 10; j++) if(res < b*(j+1)) break; res = res - b*j; } return res; } bigInt operator += (const bigInt& b) { *this = *this + b; return *this; } }; istream& operator >> (istream& in, bigInt& x) { string s; in >> s; x = s.c_str(); return in; } ostream& operator << (ostream& out, const bigInt& x) { out << x.str(); return out; } int N, M; bigInt mat[MAX_N]; bigInt mul[MAX_N]; bigInt f[MAX_N][MAX_N]; bigInt dp() { bigInt cur; for (int i = 0; i < M; i++) { for (int j = M-1; j > i; j--) { // cout << "f[" << i << "][" << j << "] = " << f[i][j] << ":" << endl; // cout << "f[" << i << "][" << j-1 << "] = " << f[i][j-1] << ' ' << "f[" << i+1 << "][" << j << "] = " << f[i+1][j] << endl; f[i][j-1] = max(f[i][j-1], f[i][j] + mul[M-(j-i+1)+1]*mat[j]); f[i+1][j] = max(f[i+1][j], f[i][j] + mul[M-(j-i+1)+1]*mat[i]); // cout << "f[" << i << "][" << j-1 << "] = " << f[i][j-1] << ' ' << "f[" << i+1 << "][" << j << "] = " << f[i+1][j] << endl; } } for (int i = 0; i < M; i++) { cur = max(cur, f[i][i] + mul[M]*mat[i]); } // cout << cur << endl; return cur; } int main() { cin >> N >> M; mul[0] = 1; for (int i = 1; i < MAX_N; i++) mul[i] = mul[i-1] * 2; bigInt ans; while (N--) { for (int i = 0; i < M; i++) { cin >> mat[i]; } for (int i = 0; i < M; i++) for (int j = i; j < M; j++) f[i][j] = 0; ans = ans + dp(); } //模板居然出了bug,怕是在硬盘里吃灰吃多了 while (ans.d[ans.len-1] > 10) { ans.d[ans.len] = ans.d[ans.len-1] / 10; ans.d[ans.len-1] %= 10; ans.len++; } cout << ans << endl; return 0; }