NOIP2007 矩阵取数游戏

3. 矩阵取数游戏

(game.pas/c/cpp)

【问题描述】

    帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n*m 的矩阵,矩阵中的每个元素 aij

为非负整数。游戏规则如下:

  1. 每次取数时须从每行各取走一个元素,共 n 个。m 次后取完矩阵所有元素;
  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
  3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2i,其中 i 表示第 i 次取数(从 1 开始编号);
  4. 游戏结束总得分为 m 次取数得分之和。

帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

 

【输入】

    输入文件game.in包括 n+1 行:

    第 1 行为两个用空格隔开的整数 n m

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

 

【输出】

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

 

【输入输出样例1】

game.in

game.out

2 3

1 2 3

3 4 2

82

 

【输入输出样例1解释】

第 1 次:第 1 行取行首元素,第 2 行取行尾元素,本次得分为 1*21+2*21=6

第 2 次:两行均取行首元素,本次得分为 2*22+3*22=20

                 3    3

第 3 次:得分为 3*2 +4*2 =56。总得分为 6+20+56=82

【输入输出样例2】

game.in

game.out

1 4

4 5 0 5

122

 

【输入输出样例3】

game.in

game.out

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<=n, m<=30, 答案不超过 1016

    100%的数据满足:1<=n, m<=80, 0<=aij<=1000

 

【思路】

  区间DP+高精度

  可以从题目中看出每一行的选取都是独立的,而每一行的最优解共同构成答案,因此对n行分别求解。

  对一行而言,状态转移方程:

      D[i][j]=max{d[i+1][j]+sq[tmp]*A[i], d[i][j-1]+A[j]*sq[tmp] };

      (tmp=n+i-j , sq[i]定义为2^i)

 

  就数据来看我们需要用到高精度。

 【代码】

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<vector>
  5 #define FOR(a,b,c) for(int a=(b);a<(c);a++)
  6 using namespace std;
  7 
  8 typedef long long LL;
  9 const int maxn= 80+5;
 10 const int MAXN = 410;
 11 
 12 struct bign
 13 {
 14     int len, s[MAXN];
 15     bign ()
 16     {
 17         memset(s, 0, sizeof(s));
 18         len = 1;
 19     }
 20     bign (int num) { *this = num; }
 21     bign (const char *num) { *this = num; }
 22     bign operator = (const int num)
 23     {
 24         char s[MAXN];
 25         sprintf(s, "%d", num);
 26         *this = s;
 27         return *this;
 28     }
 29     bign operator = (const char *num)
 30     {
 31         for(int i = 0; num[i] == '0'; num++) ;  //è¥?°μ?0
 32         len = strlen(num);
 33         for(int i = 0; i < len; i++) s[i] = num[len-i-1] - '0';
 34         return *this;
 35     }
 36     bign operator + (const bign &b) const //+
 37     {
 38         bign c;
 39         c.len = 0;
 40         for(int i = 0, g = 0; g || i < max(len, b.len); i++)
 41         {
 42             int x = g;
 43             if(i < len) x += s[i];
 44             if(i < b.len) x += b.s[i];
 45             c.s[c.len++] = x % 10;
 46             g = x / 10;
 47         }
 48         return c;
 49     }
 50     bign operator += (const bign &b)
 51     {
 52         *this = *this + b;
 53         return *this;
 54     }
 55     void clean()
 56     {
 57         while(len > 1 && !s[len-1]) len--;
 58     }
 59     bign operator * (const bign &b) //*
 60     {
 61         bign c;
 62         c.len = len + b.len;
 63         for(int i = 0; i < len; i++)
 64         {
 65             for(int j = 0; j < b.len; j++)
 66             {
 67                 c.s[i+j] += s[i] * b.s[j];
 68             }
 69         }
 70         for(int i = 0; i < c.len; i++)
 71         {
 72             c.s[i+1] += c.s[i]/10;
 73             c.s[i] %= 10;
 74         }
 75         c.clean();
 76         return c;
 77     }
 78     bign operator *= (const bign &b)
 79     {
 80         *this = *this * b;
 81         return *this;
 82     }
 83     bign operator - (const bign &b)
 84     {
 85         bign c;
 86         c.len = 0;
 87         for(int i = 0, g = 0; i < len; i++)
 88         {
 89             int x = s[i] - g;
 90             if(i < b.len) x -= b.s[i];
 91             if(x >= 0) g = 0;
 92             else
 93             {
 94                 g = 1;
 95                 x += 10;
 96             }
 97             c.s[c.len++] = x;
 98         }
 99         c.clean();
100         return c;
101     }
102     bign operator -= (const bign &b)
103     {
104         *this = *this - b;
105         return *this;
106     }
107     bign operator / (const bign &b)
108     {
109         bign c, f = 0;
110         for(int i = len-1; i >= 0; i--)
111         {
112             f = f*10;
113             f.s[0] = s[i];
114             while(f >= b)
115             {
116                 f -= b;
117                 c.s[i]++;
118             }
119         }
120         c.len = len;
121         c.clean();
122         return c;
123     }
124     bign operator /= (const bign &b)
125     {
126         *this  = *this / b;
127         return *this;
128     }
129     bign operator % (const bign &b)
130     {
131         bign r = *this / b;
132         r = *this - r*b;
133         return r;
134     }
135     bign operator %= (const bign &b)
136     {
137         *this = *this % b;
138         return *this;
139     }
140     bool operator < (const bign &b)
141     {
142         if(len != b.len) return len < b.len;
143         for(int i = len-1; i >= 0; i--)
144         {
145             if(s[i] != b.s[i]) return s[i] < b.s[i];
146         }
147         return false;
148     }
149     bool operator > (const bign &b)
150     {
151         if(len != b.len) return len > b.len;
152         for(int i = len-1; i >= 0; i--)
153         {
154             if(s[i] != b.s[i]) return s[i] > b.s[i];
155         }
156         return false;
157     }
158     bool operator == (const bign &b)
159     {
160         return !(*this > b) && !(*this < b);
161     }
162     bool operator != (const bign &b)
163     {
164         return !(*this == b);
165     }
166     bool operator <= (const bign &b)
167     {
168         return *this < b || *this == b;
169     }
170     bool operator >= (const bign &b)
171     {
172         return *this > b || *this == b;
173     }
174     string str() const
175     {
176         string res = "";
177         for(int i = 0; i < len; i++) res = char(s[i]+'0') + res;
178         return res;
179     }
180 };
181 
182 istream& operator >> (istream &in, bign &x)
183 {
184     string s;
185     in >> s;
186     x = s.c_str();
187     return in;
188 }
189 
190 ostream& operator << (ostream &out, const bign &x)
191 {
192     out << x.str();
193     return out;
194 }
195 
196 bign d[maxn][maxn];
197 bign A[maxn][maxn];
198 bign sq[maxn];
199 bign ans=0;
200 int n,m;
201 
202 int main() {
203     ios::sync_with_stdio(false);
204     cin>>n>>m;
205     FOR(i,1,n+1) FOR(j,1,m+1) cin>>A[i][j];
206     sq[0]=1; FOR(i,1,m+1){ sq[i]=sq[i-1]*2;}   //高精单精乘 
207     FOR(T,1,n+1){
208       FOR(l,0,m) FOR(i,1,m-l+1) {  //m
209             int j=i+l , tmp=m+i-j;
210              if(l==0) { d[i][i]=A[T][i]*sq[tmp];continue; } 
211              bign v1=d[i+1][j]+A[T][i]*sq[tmp] ,v2= d[i][j-1]+A[T][j]*sq[tmp] ;
212             if(v1>v2)  d[i][j]=v1;  else d[i][j]=v2;   //高精赋值 
213       }
214       ans = ans + d[1][m];  //高精高精加 
215     }
216     cout<<ans;
217     return 0;
218 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值