zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    sql查询自然数判断
    esayswool_admin的3个坑
    debian安装easyswoole
    微软浏览器冲浪小游戏
    php程序的安装和composer
    图片搬运工
    热血高校这部电影中的内含文化
    Google日本語入力的使用方法,基本的快捷键。
    PHP截取两个指定字符中间的字符
    php去除字符串中的HTML标签
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4859444.html
Copyright © 2011-2022 走看看