zoukankan      html  css  js  c++  java
  • CF 321D

    大概题意:

    有一个N*N的矩阵,N恒为奇数,设X=(N+1)/2,我们每次可以对其中X*X的子矩阵进行正负取反的操作,问经过操作可以得到的矩阵和的Max 

    (N<=33)

    Eg.

    Input

    3 -1 -1

    1 -1 1

    -1 1 -1

    Output

    9

    Hint;

    3 -1 -1       3 1 1           3 1 1           3 1 1

    1 -1  1   -> 1 1 -1  ->    1 -1 1 ->      -1 1 1

    -1 1 -1       -1 1 -1       -1 -1 1           1 1 1

    解法:

    我们发现x=(n+1)/2,所以有一个很重要的结论。

    设f[i][j]表示(i,j)这个格是否翻转,那么有f[i][j]^f[i][x]^f[i][j+x]=0,f[i][j]^f[x][j]^f[i+x][j]=0

    因为一次操作范围为x*x,一定同时覆盖三者中的两者,所以无论怎么操作它们异或的值恒为0。

    我们发现整个N*N的方格可以被分成四个部分。

    而且每个区内对应的四个格子是独立的,可以单独的计算。

    因此我们只需枚举中间那一行一列的值,然后对于如图所示的四个格子单独贪心地计算即可。复杂度O(2^N*N^2)。

    但这样仍然会超时!

    随着研究我们发现,行与行之间也是独立的,我们不需要枚举中间一列的每个状态,而是枚举完中间一行后,对于行逐行单独贪心计算,复杂度变为O(2^X*X^2),可以通过此题

    End.

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    
    using namespace std;
    
    int a[41][41],col[41],f[41];
    int ans,n,i,j,x;
    int g[35][35][2][2][2];
    bool vs[35][35][2][2][2];
    
    int Test(int y,int z)
    {
        int ts,tt,res,i,nt;
        nt=col[x]^z;
        res=0;
        if(z)res-=a[y][x];
        else res+=a[y][x];
        if(nt)res-=a[y+x][x];
        else res+=a[y+x][x];
        for(i=1;i<x;i++){
            if(vs[y][i][col[x]][z][col[i]])res+=g[y][i][col[x]][z][col[i]];
            else{
                f[1]=1;f[2]=f[1]^z;f[3]=f[1]^col[i];f[4]=f[3]^nt;
                ts=0;
                if(f[1])ts-=a[y][i];
                else ts+=a[y][i];
                if(f[2])ts-=a[y][i+x];
                else ts+=a[y][i+x];
                if(f[3])ts-=a[y+x][i];
                else ts+=a[y+x][i];
                if(f[4])ts-=a[y+x][i+x];
                else ts+=a[y+x][i+x];
                f[1]=0;f[2]=f[1]^z;f[3]=f[1]^col[i];f[4]=f[3]^nt;
                tt=0;
                if(f[1])tt-=a[y][i];
                else tt+=a[y][i];
                if(f[2])tt-=a[y][i+x];
                else tt+=a[y][i+x];
                if(f[3])tt-=a[y+x][i];
                else tt+=a[y+x][i];
                if(f[4])tt-=a[y+x][i+x];
                else tt+=a[y+x][i+x];
                res+=max(ts,tt);
                vs[y][i][col[x]][z][col[i]]=true;
                g[y][i][col[x]][z][col[i]]=max(ts,tt);
            }
        }
        return res;
        
    }
    
    void Work(int zt)
    {
        int i,tmp;
        for(i=1;i<=x;i++){
            if((zt&(1<<(i-1))))col[i]=1;
            else col[i]=0;
        }
        for(i=x+1;i<=n;i++)col[i]=col[x]^col[i-x];
        tmp=0;
        for(i=1;i<=n;i++){
            if(col[i])tmp-=a[x][i];
            else tmp+=a[x][i];
        }
        for(i=1;i<x;i++)tmp+=max(Test(i,0),Test(i,1));
        if(tmp>ans)ans=tmp;
    }
    
    int main()
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)scanf("%d",&a[i][j]);
        x=(n+1)/2;
        ans=-2147483647;
        for(i=0;i<(1<<x);i++)Work(i);
        printf("%d
    ",ans);
    }
  • 相关阅读:
    easy-ui的data-options用法
    my_note
    定时器
    abp安装
    微信小程序
    几个免费的ui 后台
    abp创建实体的方法
    winform 开源项目
    func委托
    for update 锁行和锁表
  • 原文地址:https://www.cnblogs.com/applejxt/p/4593907.html
Copyright © 2011-2022 走看看