NOIP2007矩阵取数游戏

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

NOIP2007矩阵取数游戏的相关文章

NOIP2007 矩阵取数游戏

题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均 为非负整数.游戏规则如下: 1. 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. 每次取走的各个元素只能是该元素所在行的行首或行尾: 3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素值*2i, 其中i 表示第i 次取数(从1 开始编号): 4. 游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个

Noip2007矩阵取数游戏题解

题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n?m的矩阵,矩阵中的每个元素ai,j均 为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 每次取走的各个元素只能是该元素所在行的行首或行尾: 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分=被取走的元素值?2i, 其中i表示第i 次取数(从1 开始编号): 游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出

矩阵取数游戏 NOIP 2007

2016-05-31 17:26:45 题目链接: NOIP 2007 矩阵取数游戏(Codevs) 题目大意: 给定一个矩阵,每次在每一行的行首或者行尾取一个数乘上2^次数,求取完最多获得的分数 解法: 动态规划 DP[i][j]表示当前行i位置到j位置获得的最大分数 转移方程: DP[i][j]=max(DP[i+1][j]+a[i]*2^x,DP[i][j-1]+a[i]*2^x); 需要注意的地方: 1.M和N给的范围略坑啊,2^80只有悄悄不说话了,所以直接上了100000的压位,感觉

矩阵取数游戏

题目描述 Description [问题描述]帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下:1. 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素:2. 每次取走的各个元素只能是该元素所在行的行首或行尾:3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素值*2i,其中i 表示第i 次取数(从1 开始编号):4. 游戏结束总得分为m次取数得分之和.帅帅想请你帮忙写一个程序,对于任意矩

P1005矩阵取数游戏

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分. 输入输

矩阵取数游戏洛谷p1005

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分. 输入输

洛谷 P1005 矩阵取数游戏 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1005 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元

P1005 矩阵取数游戏

P1005 矩阵取数游戏 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出

NOIP2007矩阵取数[DP|高精度]

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分. 输入输