BZOJ3517 翻硬幣
阿新 • • 發佈:2018-09-25
std ring pen || pac etc turn 翻硬幣 span
最後翻為0和1本質相同,只考慮一種。顯然每個硬幣最多翻一次。考慮設xi,j表示i,j位置的硬幣是否翻,那麽很容易就可以列出異或方程組。變量和方程都有n2個,那麽解是唯一的,就不用考慮怎樣最小化了。然而暴力高斯消元肯定是不行的。
考慮將所有關於xi,k和xk,j的方程疊加,由於n是偶數,可以得到xi,j=ai,k^ak,j^ai,j (k=1~n)。於是就解出來了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 1010 int n,a[N][N],s[2][N],ans; int main() { #ifndef ONLINE_JUDGE freopen("bzoj3517.in","r",stdin); freopen("bzoj3517.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) { char c=getchar(); while (c!=‘0‘&&c!=‘1‘) c=getchar(); for (int j=1;j<=n;j++) a[i][j]=c^48,c=getchar(); } for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) s[0][i]^=a[i][j],s[1][j]^=a[i][j]; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) ans+=s[0][i]^s[1][j]^a[i][j]; cout<<min(ans,n*n-ans); return 0; }
BZOJ3517 翻硬幣