1 条题解

  • 0
    @ 2023-4-12 18:40:30

    点我博客食用更佳

    (注:新oj由于数据过弱,甚至可能可以不用int128(我没试过doge))

    矩阵取数游戏


    ~众所周知,一般而言,随着经济社会的发展...~

    (以上省略114514字)...今天,小编就来给大家带来矩阵取数游戏的...


    首先介绍一个知识:

    __int128!

    首先,int128和普通的int在运算上没什么不同,但是 数据范围是ll的平方!

    但是两者还是有点区别的。比如:

    int128不能直接cin>>读取和cout<<输出,所以要自己写一个快读快输。

    借助高精思路,甚至不需要太多,就能得出快读快写:

    inline void input(__int128 &s)
    {
        s=0;
        char c=' ';
        while(c>'9'||c<'0') c=getchar();
        while(c>='0'&&c<='9')
        {
            s=s*10+c-'0';
            c=getchar();
        }
    }
    
    inline void output(__int128 x)
    {
        if(x>9)
            output(x/10);
        putchar(x%10+'0');
    }
    

    而本题,很明显需要使用区间DP。(注:一下num均表示一行 ​~(三维数组也问题不大)~​。)

    以nu[i][j]表示所有数字(当然也可以用一个随时重置的一维数组)每行将一个nu[i]传到函数里,函数的参数是一个一维数组nn[],这样读更加方便一点.

    使用num[i][j]来储存每行区间[i,j]的最大结果。由于DP的最优解原理,每个[i,j]都是当前状态下最大值。

    通过遍历从0-m的步长l,再遍历i为1-m,设j=i+m,可得出以下结论:

    而每个num[i][j]都是由num[i-1][j]取nn[i]或num[i][j+1]取num[j]计算而来的。

    再看提议,其实强算也问题不大,但更建议使用题解里的一种算法。由于每次是取自身的2^n,故每次取点可看作先取一次自己,然后对后面的总数进行一次*2

    所以可以得出转移方程:

    num[i][j]=max(2 num[i-1][j] + 2 a[i], 2 num[i][j+1] + 2 a[j])

    以下代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    inline void input(__int128 &s)
    {
        s=0;
        char c=' ';
        while(c>'9'||c<'0') c=getchar();
        while(c>='0'&&c<='9')
        {
            s=s*10+c-'0';
            c=getchar();
        }
    }
    
    inline void output(__int128 x)
    {
        if(x>9)
            output(x/10);
        putchar(x%10+'0');
    }
    
    __int128 ans=0;
    __int128 nu[90][90],num[90][90];
    int n,m;
    
    __int128 line(__int128 nn[])
    {
        for(int l=0;l<=m;l++){
            for(int i=1;i<=m-l;i++){
                int k=i+l;
                num[i][k]=max(2*num[i+1][k]+2*nn[i],2*num[i][k-1]+2*nn[k]);
            }
        }
        return num[1][m];
    }
    
    signed main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            memset(num,0,sizeof(num));
            for (int j=1;j<=m;j++){
                input(nu[i][j]);
            }
            ans+=line(nu[i]);
        }
        output(ans);
        return 0;
    }
    
    • 1

    信息

    ID
    263
    时间
    2000ms
    内存
    64MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者