[LuoguP1005]矩阵取数游戏 (DP+高精度)

题面

传送门:https://www.luogu.org/problemnew/show/P1005

Solution

我们可以先考虑贪心

我们每一次都选左右两边尽可能小的数,方便大的放在后面

听起来挺OK的

实则并不OK

反例:

3 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2

如果贪心的话,我们会优先把右边那一串2先选了,再去选3和1

但是正确答案显然是先把3和1选了,再去选那一串2



既然贪心不成,我们可以考虑一下DP

然后我们考虑这样一个状态:

f[i][j][k] 表示第i时刻,第j行,左边选到了第k列

因为我们知道了当前时刻和左边选到的列数,右边选到的列数也可以推算出来: m-i+k-1

然后就可以写出来一个比较显然的转移方程:

f[i][j][k]=max(f[i-1][j][k-1]+2^i*num[j][k-1],f[i-1][j][k]+2^i*num[j][m-i+k]) 

也就是第i时刻是选最左边的还是选右边的



这样子我们就可以得到 100分 60分

为什么会变成这样的呢?

原因很简单,我们仔细看一下数据范围:80

也就是说数据大小至少会有2^80

显然longlong (Int64)是放不下的

这时候,我们就需要伟大的Int128

你当然可以用stl的int128(虽然考试中不能用)

我们这里选用手写一个高精度类

我们只需要高精乘低精,高精加高精,高精比较大小

再加上若干时间的调试高精

然后就OjbK了

Code

//Luogu P1005 矩阵取数游戏
//DP+高精
//Apr,27th,2018
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct Int128
{
    int a[50],len;
    Int128()
    {
        memset(a,0,sizeof a);
        len=0;
    }
    void Insert()
    {
        char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)){a[++len]=c-‘0‘;c=getchar();}
        int tot=len/2;
        for(int i=len;i>tot;i--)swap(a[i],a[len-i+1]);
    }
    void Print()
    {
        for(int i=len;i>=1;i--)
            printf("%d",a[i]);
    }
    friend Int128 operator * (Int128 a,int b)
    {
        Int128 ans=Int128();
        ans.len=a.len;
        for(int i=1;i<=ans.len;i++)
        {
            ans.a[i]+=a.a[i]*b;
            ans.a[i+1]+=ans.a[i]/10;
            ans.a[i]%=10;
            if(i==ans.len and ans.a[i+1]!=0)
                ans.len++;
        }
        return ans;
    }
    friend Int128 operator + (Int128 a,Int128 b)
    {
        Int128 ans=Int128();
        ans.len=max(a.len,b.len);
        for(int i=1;i<=ans.len;i++)
        {
            ans.a[i]+=a.a[i]+b.a[i];
            ans.a[i+1]+=ans.a[i]/10;
            ans.a[i]%=10;
            if(i==ans.len and ans.a[i+1]!=0)
                ans.len++;
        }
        return ans;
    }
    friend bool operator < (Int128 a,Int128 b)
    {
        if(a.len<b.len) return true;
        if(a.len>b.len) return false;
        for(int i=a.len;i>=1;i--)
            if(a.a[i]>b.a[i])
                return false;
            else if(a.a[i]<b.a[i])
                return true;
        return false;
    }
};
const int N=80+10;
Int128 f[2][N][N],POW[N];
int a[N][N];
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);

    POW[1].len=1,POW[1].a[1]=2;
    for(int i=2;i<=m;i++)
        POW[i]=POW[i-1]*2;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=i+1;k++)
            {
                if(k>1)
                    f[i%2][j][k]=f[(i-1)%2][j][k-1]+POW[i]*a[j][k-1];
                if(m-i+k-1<m)
                    f[i%2][j][k]=max(f[i%2][j][k],f[(i-1)%2][j][k]+POW[i]*a[j][m-i+k]);
                //f[i%2][j][k].Print();
                //cout<<endl;
            }

    Int128 ans=Int128();
    for(int i=1;i<=n;i++)
    {
        Int128 t_ans=Int128();
        for(int j=1;j<=m;j++)
            t_ans=max(t_ans,f[m%2][i][j]);
        ans=ans+t_ans;
    }

    ans.Print();
    return 0;
}

原文地址:https://www.cnblogs.com/GoldenPotato/p/8964121.html

时间: 2024-10-23 09:38:27

[LuoguP1005]矩阵取数游戏 (DP+高精度)的相关文章

[luoguP1005] 矩阵取数游戏(DP + 高精度)

传送门 和奶牛那个题很像,每一行状态互不影响,也就是求 n 遍DP 不过高精度非常恶心,第一次写,调了我一上午. ——代码 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 struct Big_int 6 { 7 int s[35], idx; 8 Big_int() 9 { 10 idx = 0; 11 memset(s, 0, sizeof(s)); 12 } 13 }; 14 1

dp+高精度(洛谷1005 矩阵取数游戏NOIP 2007 提高第三题)

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

1166 矩阵取数游戏[区间dp+高精度]

1166 矩阵取数游戏 2007年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description [问题描述]帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下:1. 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素:2. 每次取走的各个元素只能是该元素所在行的行首或行尾:3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分

【日常学习】【区间DP+高精】codevs1166 矩阵取数游戏题解

题目来自NOIP2007TG3 如果在考场上我现在已经歇菜了吧 今天一整天的时间全部投在这道题上,收获不小. 先上题目 题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均 为非负整数.游戏规则如下: 1. 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. 每次取走的各个元素只能是该元素所在行的行首或行尾: 3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素

矩阵取数游戏

题目描述 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 矩阵取数游戏 题解

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

洛谷 P1005 矩阵取数游戏

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

Noip2007矩阵取数游戏题解

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