码迷,mamicode.com
首页 > 其他好文 > 详细

NOIP2007矩阵取数游戏

时间:2015-09-12 18:54:58      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:

眼看就要刷完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;
}

 

NOIP2007矩阵取数游戏

标签:

原文地址:http://www.cnblogs.com/GENEVE/p/4803282.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!