Bzoj3517 翻硬幣題解
阿新 • • 發佈:2017-10-15
%d output gre space 包含 [1] printf 呵呵 con
Submit: 281 Solved: 211
[Submit][Status][Discuss]
4
0101
1000
0010
0101
3517: 翻硬幣
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 281 Solved: 211
[Submit][Status][Discuss]
Description
有一個n行n列的棋盤,每個格子上都有一個硬幣,且n為偶數。每個硬幣要麽是正面朝上,要麽是反面朝上。每次操作你可以選定一個格子(x,y),然後將第x行和第y列的所有硬幣都翻面。求將所有硬幣都變成同一個面最少需要的操作數。Input
第一行包含一個正整數n。 接下來n行,每行包含一個長度為n的01字符串,表示棋盤上硬幣的狀態。Output
僅包含一行,為最少需要的操作數。Sample Input
0101
1000
0010
0101
Sample Output
2HINT
【樣例說明】
對(2,3)和(3,1)進行操作,最後全變成1。
【數據規模】
對於100%的數據,n ≤ 1,000。
上來一看,第一反應,異或數學題,想了半天如何異或也沒想出來,問呵呵酵母菌,他說他覺得是圖論WTF?!圖論有幾個O(n)算法能在這道題用上的。
於是乎看了一眼題解:解異或方程組……
一個點最多翻一遍,這話不用再說了吧……
讓我們先從都翻為0開始說起
我們設x[i][j]為第i,j個點是否要翻,a[i][j]為該點初始狀態,則x[1][j]^x[2][j]^……^x[n][j]^x[i][1]^x[i][2]^x[i][m]^x[i][j]=a[i][j]。
我們把第i行和第j列所有的點按照上式列出方程組並合並, 由於n為偶數,則可以化為:
x[i][j]=a[1][j]^a[2][j]^……^a[n][j]^a[i][1]^a[i][2]^……^a[i][m]^a[i][j]。
那麽我們只要對於每一行,每一列n^2預處理出他們的異或和再相加就好了。
至於都為1嗎?由於n是偶數,我們只要把每一個點是否翻的狀態取反就是答案。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5View Code#include <queue> 6 #include <algorithm> 7 #include <cmath> 8 #include <map> 9 #define N 1005 10 using namespace std; 11 int n,a[N][N]; 12 char b[N]; 13 int sum[2][N]; 14 int main() 15 { 16 scanf("%d",&n); 17 for(int i=1;i<=n;i++) 18 { 19 scanf("%s",b+1); 20 for(int j=1;j<=n;j++) 21 { 22 a[i][j]=b[j]-‘0‘; 23 } 24 } 25 for(int i=1;i<=n;i++) 26 { 27 for(int j=1;j<=n;j++) 28 { 29 sum[0][i]^=a[i][j]; 30 sum[1][j]^=a[i][j]; 31 } 32 } 33 int ans=0; 34 for(int i=1;i<=n;i++) 35 { 36 for(int j=1;j<=n;j++) 37 { 38 int t=sum[0][i]^sum[1][j]; 39 t^=a[i][j]; 40 ans+=t; 41 } 42 } 43 ans=min(ans,n*n-ans); 44 printf("%d\n",ans); 45 return 0; 46 }
Bzoj3517 翻硬幣題解