1. 程式人生 > >【貪心】【P2117】小Z的矩陣

【貪心】【P2117】小Z的矩陣

put 正整數 通過 new template null 輸出 org scrip

傳送門

Description

小Z最近迷上了矩陣,他定義了一個對於一種特殊矩陣的特征函數G。對於N*N的矩陣A,A的所有元素均為0或1,

當然詢問一個矩陣的G值實在是太簡單了。小Z在給出一個N*N矩陣的同時將給你Q個操作,操作描述如下:

操作1:形如一個整數1和一個整數x,表示將第x行的元素全部“翻轉”。

操作2:形如一個整數2和一個整數x,表示將第x列的元素全部“翻轉”。

操作3:形如一個整數3,表示詢問當前矩陣的特征值G。

“翻轉”的定義為將1變成0,將0變成1。

Input

第1行:兩個正整數N,Q。 N表示矩陣的行數(列數),Q表示詢問的個數。

接下來N行:一個N*N的矩陣A,0<=A[i][j]<=1。

接下來Q行:Q個操作。

Output

一行若幹個數,中間沒有空格,分別表示每個操作的結果(操作1和操作2不需要輸出)。

Sample Input

3 12
1 1 1
0 1 1
1 0 0
3
2 3
3
2 2
2 2
1 3
3
3
1 2
2 1
1 1
3

Sample Output

01001

Hint

30% N<=100, Q<=10^5

100% N<=1,000, Q <=5*10^5

Solution

對於30%,O(NQ)暴力出奇跡

對於100%,我們考慮這樣一個事實:對於所有的i!=j,會計算四次A,其中通過(i,j)計算A[i][j]*A[j][i],,通過(j,i)計算A[j][i]*A[i][j]。不難發現,無論A[i][j]*A[j][i]等於0還是等於1,相加後取模2恒等於零。

數學證明如下:對於ans=Σ(A[i][j]*A[j][i]+A[i][j]*A[j][i])(i<j) Mod 2=Σ2(A[i][j]*A[j][i]) Mod 2=2*Σ(A[i][j]*A[j][i]) Mod 2=0

所以對於i!=j矩陣元素對答案沒有貢獻。

所以ans=ΣA[i][i] Mod 2。每次修改 ans^=1即可。

Code

#include<cstdio>
#define ci const int

inline void qr(int &x) {
    char ch=getchar(),lst=NULL;
    
while(ch>9||ch<0) lst=ch,ch=getchar(); while(ch>=0&&ch<=9) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); if (lst==-) x=-x; } char buf[20]; inline void write(int x,const char aft,const bool pt) { if(x<0) {putchar(-);x=-x;} int top=0; do { buf[++top]=x%10+0; x/=10; } while(x); while(top) putchar(buf[top--]); if(pt) putchar(aft); } template <typename T> inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;} template <typename T> inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;} template <typename T> inline T mabs(const T &a) {if(a<0) return -a;return a;} template <typename T> inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;} int n,m,a; bool ans; int main() { qr(n);qr(m); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(i!=j) qr(a);else {a=0;qr(a);if(a) ans^=1;} while(m--) {a=0;qr(a);if(a==3) {if(ans) putchar(1);else putchar(0);}else {qr(a);ans^=1;}} putchar(\n); return 0; }

Summary

對於計算了兩遍然後答案Mod 2的元素,可以直接pass。

真tm神仙

【貪心】【P2117】小Z的矩陣