链接:
#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/44793957");
}
~~~
貌似是wyfcyx以前出过的题?
题解:
那个首先暴力的话并不是O(217),而是O(217?17)。
然后我们分析怎么过此题。
首先我们发现其实搜索的话,有好几部分都是独立的。
发现所有的方形都经过中间一行,所以我们可以先O(217)枚举中间一行左边一半的取反状态,然后右边的一半可以递推出来,有点像异或前缀和,看代码吧。
然后对每一列O(217)处理,时间复杂度差不多了,但是还是挂的。
我们发现还能拆。
我们对每一行进行处理,这样就可以不决定中间一列,只决定中间一点的取反与否。
然后枚举行内每个点,看它状态,这样把每一行的每一对点的决策最优值加到中间一点取反与否的两个函数值上,最后再把函数值取优返还给这一列的决策(思想上),整列就是当前枚举集合的最优答案。
所有最优答案中的最优就是全局最优答案。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 35
using namespace std;
int a[N][N],n,m,ans;
bool v[N]; // 表示翻转1,不翻转0
int main()
{
freopen("test.in","r",stdin);
int i,j,k;
scanf("%d",&n),m=n+1>>1;
for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%d",&a[i][j]);
for(int S=(1<<m)-1;~S;S--)
{
int sum=0;
for(i=1;i<=m;i++)
{
v[i]=(S>>i-1)&1;
if(v[i])sum-=a[m][i];
else sum+=a[m][i];
}
for(i=m+1;i<=n;i++)
{
v[i]=v[m]^v[i-m];
if(v[i])sum-=a[m][i];
else sum+=a[m][i];
}
for(i=1;i<m;i++)
{
int x=-a[i][m],y=a[i][m]; // x翻转,y不翻转
if(v[m])x+=a[i+m][m],y-=a[i+m][m];
else x-=a[i+m][m],y+=a[i+m][m];
for(j=1;j<m;j++)
{
int p,q;
if(v[j])
{
p=-a[i][j]+a[i][j+m]+a[i+m][j];
q=-a[i][j]-a[i][j+m]+a[i+m][j];
if(v[m])p+=a[i+m][j+m],q-=a[i+m][j+m];
else p-=a[i+m][j+m],q+=a[i+m][j+m];
p=max(p,-p),q=max(q,-q); // 很巧,,
}
else
{
p=-a[i][j]+a[i][j+m]-a[i+m][j];
q=-a[i][j]-a[i][j+m]-a[i+m][j];
if(v[m])p-=a[i+m][j+m],q+=a[i+m][j+m];
else p+=a[i+m][j+m],q-=a[i+m][j+m];
p=max(p,-p),q=max(q,-q);
}
x+=p,y+=q;
}
sum+=max(x,y);
}
ans=max(ans,sum);
}
cout<<ans<<endl;
return 0;
}
时间: 2024-10-12 12:32:23