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\n",ans);
}

 

posted on 2015-06-22 21:18  razorjxt  阅读(552)  评论(0编辑  收藏  举报