解法:
我们发现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); }