题解 CF321D 【Ciel and Flipboard】
orz wfj_2048
Tag:我也不知道叫什么,叫思维题吧。。
Step1 性质
设
那么有
因为第i行这三个点要么被翻到2个要么0个
同理列也有这个性质
Step2 推导
那么我们枚举左上的一个四分之一矩形就可以对称出所有位置了
同时会发现,在
当
继续优化
如果只枚举
由此,只需要枚举
代码极好理解
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int r[40][40],v[40][40],n,m,ans=-1e9;
int F(int x,int y){return r[x][y]?-v[x][y]:v[x][y];}
int query(int x,int y,int d)
{
r[x][y]=d; r[x+m][y]=r[m][y]^d;
r[x][y+m]=r[x][m]^d;
r[x+m][y+m]=r[m][y+m]^r[x][y+m];
return F(x,y)+F(x+m,y)+F(x,y+m)+F(x+m,y+m);
}
int query(int y,int d)
{
int res=0; r[m][y]=d; r[m][y+m]=r[m][m]^d;
res+=F(m,y)+F(m,y+m);
for(int x=1;x<m;x++) res+=max(query(x,y,0),query(x,y,1));
return res;
}
int Calc()
{
int res=0; for(int x=1;x<=n;x++) res+=F(x,m);
for(int y=1;y<m;y++) res+=max(query(y,0),query(y,1));
return res;
}
int main()
{
scanf("%d",&n); m=(n+1)>>1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&v[i][j]);
for(int zt=0;zt<(1<<m);zt++)
{
for(int x=1;x<=m;x++) r[x][m]=zt>>(x-1)&1;
for(int x=1;x<m;x++) r[x+m][m]=r[m][m]^r[x][m];
ans=max(ans,Calc());
}
printf("%d\n",ans);
}
虽然和本题完全没有关系但是还是打个广告「blog」