题型:数论
题意:
n*n的矩阵,元素是0或1。
定义一种运算:ans = ∑(Aij*Aji),且都是模2运算。
现有三种指令:
(1)1 row:把第row行的的每个元素都反转
(2)2 column:把第column列的每个元素都反转
(3)3:输出运算的解
分析:
不用多说,指令数多达10^6,每次都傻傻的暴力一定呵呵。
由于是模2运算,则有如下特性:
对于加法‘+’:1+1=0
0+0=0
1+0=0
0+1=0
对于乘法‘*’: 1*1=1
1*0=0
0*1=0
0*0=0
尝试分析一下3*3的矩阵:
A11 A12 A13 A11*A11+A12*A21+A13*A31
A21 A22 A23 = + A12*A21+A22*A22+A32*A23 = A11*A11+A22*A22+A33*A33+0
A31 A32 A33 + A13*A31+A23*A32+A33*A33
对于每次的反转指令,都等价于修改了主对角线上的一个元素,也就是说在上面推出的式子中,要么多了一个1,要么少了一个1,再考虑一下‘+’的性质,可知每次翻转指令都会将运算结果翻转。
至此,问题解决~
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n,m;
int a[1005][1005];
int s[1005];
int add(int a,int b){
if(a+b==1) return 1;
else return 0;
}
int main(){
while(~scanf("%d",&n)){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&a[i][j]);
}
}
for(int i=0;i<n;i++){
s[i] = 0;
for(int j=0;j<n;j++){
s[i] = add(s[i],(a[i][j]&a[j][i]));
}
}
int ans = 0;
for(int i=0;i<n;i++){
ans = add(ans,s[i]);
}
scanf("%d",&m);
int id,num;
while(m--){
scanf("%d",&id);
if(id==3) printf("%d",ans);
else{
scanf("%d",&num);
if(ans==0) ans=1;
else ans=0;
}
}
puts("");
}
return 0;
}