眼看就要刷完NOIP2007了,然而我忽然想放弃了,咱家图论崩的一B,最后一题可能要推迟放出了,咱们返回正题:矩阵取数
题目简述:给你一个n*m的矩阵,每次从每一行的行头或行末取出一个数,这个数乘上2 ^ i (i 是 第几次取数) 加到answer中,求answer的最大值
你是不是有一种贪心的冲动?我就无脑写了一个,对于每次的两个选择中取较小的数,加到answer中,然而三组样例只能过一组。
贪心是不可行的,证明呢,由程序完成。让我们来想想正解应该怎么写吧,具体的分析过后我们可以发现一个隐含条件:矩阵取数的最大得分是每行的最大得分之和,这样矩阵取数就可以简化成一维数组取数的问题,对于每一行,我们似乎看到了dp的方法,下面是有关转移方程的解析:
我们令score[i][len]表示现在剩下len个数字,且首个数字下标是 i 时所取到的最大值。由于只剩下len个数字,即已经取了m-len个数字,所以接下来进行的就会是第m-len+1次取数。此时的选择有两种:取前面 或者 取后面,那么我们就可以容易的得到方程:
score[i][len] = max(a[i] << (m - len + 1) + score[i + i][len - 1],a[i + len - 1] << (m - len + 1) + score[i][len - 1]);
然而又有细节要注意:m最大时80 是会爆long long 的(jave请忽略),我们要写一个神奇的结构叫做高精度,然而坑爹的oj内存给的是128000K,咱家懒嘛,就写的100*100*100*40的高精度刚好是125M = 128000K,然而又不能没有别的变量,在常数上爆了内存,最后还是降成了二维,3M妥妥的,水过了
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> using namespace std; typedef long long ll; const int Size = 40; struct bign{ int len,s[Size]; bign (){ memset(s,0,sizeof s); len = 1; } bign (int num){ *this = num;} bign (const char *num){ *this = num;} bign operator = (const int num){ char s[Size]; sprintf(s,"%d",num); *this = s; return *this; } bign operator = (const char *num){ for (int i = 0;num[i] == ‘0‘; ++num); len = strlen(num); for (int i = 0;i < len; ++i) s[i] = num[len - i - 1] - ‘0‘; return *this; } bign operator + (const bign &b) const{ bign c; c.len = 0; for (int i = 0,g = 0;g || i < max(len,b.len); ++i){ int x = g; if (i < len) x += s[i]; if (i < b.len) x += b.s[i]; c.s[c.len++] = x % 10; g = x / 10; } return c; } bign operator += (const bign &b){ *this = *this + b; return *this; } void clean(){ while (len > 1 && !s[len - 1]) len--; } bign operator * (const bign &b){ bign c; c.len = len + b.len; for (int i = 0;i < len; ++i) for (int j = 0;j < b.len; ++j) c.s[i + j] += s[i] * b.s[j]; for (int i = 0;i < c.len; ++i){ c.s[i + 1] += c.s[i] / 10; c.s[i] %= 10; } c.clean(); return c; } bign operator *= (const bign &b){ *this = *this * b; return *this; } bign operator - (const bign &b){ bign c; c.len = 0; for (int i = 0,g = 0;i < len; ++i){ int x = s[i] - g; if (i < b.len) x -= b.s[i]; if (x >= 0) g = 0; else { g = 1; x += 10; } c.s[c.len++] = x; } c.clean(); return c; } bign operator -= (const bign &b){ *this = *this - b; return *this; } bign operator / (const bign &b){ bign c,f =0; for (int i = len - 1;i >= 0; --i){ f = f * 10; f.s[0] = s[i]; while (f >= b){ f -= b; c.s[i]++; } } c.len = len; c.clean(); return c; } bign operator /= (const bign &b){ *this = *this / b; return *this; } bign operator % (const bign &b){ bign r = *this / b; r = *this - r*b; return r; } bign operator %= (const bign &b){ *this = *this % b; return *this; } bool operator < (const bign &b){ if (len != b.len) return len < b.len; for (int i = len - 1;i >= 0; --i) if (s[i] != b.s[i]) return s[i] < b.s[i]; return 0; } bool operator > (const bign &b){ if (len != b.len) return len > b.len; for (int i = len - 1;i >= 0; --i) if (s[i] != b.s[i]) return s[i] > b.s[i]; return 0; } bool operator == (const bign &b){ return !(*this > b) && !(*this < b); } bool operator != (const bign &b){ return !(*this == b); } bool operator <= (const bign &b){ return *this > b; } bool operator >= (const bign &b){ return *this < b; } string str() const { string res = ""; for (int i = 0;i < len; ++i) res=char(s[i] + ‘0‘) + res; return res; } }; int n,m; bign score[100][100],a[100][100],ans; /*const*/ bign b0,b1,b2; bign fast_power(bign a,int b){ bign c = b1; while (b){ if (b & 1) c *= a; b /= 2; a *= a; } return c; } bign max(bign a,bign b){ return a > b ? a : b; } istream& operator >> (istream &in,bign &x){ string s; in >> s; x = s.c_str(); return in; } ostream& operator << (ostream &out,const bign &x){ out << x.str(); return out; } void dp(){ for (int j = 0;j < n; ++j){ for (int i = 0; i < m; ++i) for (int j = 0; j < m; ++j) score[i][j].clean(); for (int len = 1;len <= m; ++len) for (int i = 0;i < m; ++i){ if (i + len > m) break; bign w = fast_power(b2,m - len + 1); score[i][len] = max(a[j][i] * w + score[i + 1][len - 1],a[j][i + len - 1] * w + score[i][len - 1]); } ans += score[0][m]; } } int main(){ scanf("%d%d",&n,&m); b0.len = 1,b0.s[0] = 0; b1.len = 1,b1.s[0] = 1; b2.len = 1,b2.s[0] = 2; for (int i = 0; i< n; ++i) for (int j = 0; j < m; ++j) cin >> a[i][j]; dp(); cout << ans << endl; }
时间: 2024-10-04 10:16:56