P2117 小Z的矩阵
题目描述
小Z最近迷上了矩阵,他定义了一个对于一种特殊矩阵的特征函数G。对于N*N的矩阵A,A的所有元素均为0或1,则G(A)等于所有A[i][j]*A[j][i]的和对2取余之后的结果。举一个例子:
对于上图这个3*3矩阵A,G(A)=(1*1+1*0+1*1+0*1+1*1+1*0+1*1+ 0*1+0*0) mod 2=0
当然询问一个矩阵的G值实在是太简单了。小Z在给出一个N*N矩阵的同时将给你Q个操作,操作描述如下:
操作1:形如一个整数1和一个整数x,表示将第x行的元素全部“翻转”。
操作2:形如一个整数2和一个整数x,表示将第x列的元素全部“翻转”。
操作3:形如一个整数3,表示询问当前矩阵的特征值G。
“翻转”的定义为将1变成0,将0变成1。
输入输出格式
输入格式:
第1行:两个正整数N,Q。 N表示矩阵的行数(列数),Q表示询问的个数。
接下来N行:一个N*N的矩阵A,0<=A[i][j]<=1。
接下来Q行:Q个操作。
输出格式:
一行若干个数,中间没有空格,分别表示每个操作的结果(操作1和操作2不需要输出)。
输入输出样例
说明
【数据规模】
30% N<=100, Q<=10^5
100% N<=1,000, Q <=5*10^5
紫色诱惑二:
算是一道数学找规律题,
数据范围很大,
模拟思路应该还能接受吧,题目怎么着,就怎么写,
先看一下三十分纯模拟代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 8 int n,q,x[500002],y[500002],g; 9 int a[1002][1002]; 10 11 int main() 12 { 13 scanf("%d%d",&n,&q); 14 for(int i=1;i<=n;++i) 15 for(int j=1;j<=n;++j) 16 scanf("%d",&a[i][j]); 17 for(int i=1;i<=q;++i) 18 { 19 scanf("%d",&x[i]); 20 if(x[i]!=3) 21 scanf("%d",&y[i]); 22 } 23 for(int i=1;i<=q;++i) 24 { 25 if(x[i]==3) 26 { 27 for(int j=1;j<=n;++j) 28 for(int k=1;k<=n;++k) 29 g+=a[j][k]*a[k][j]; 30 printf("%d",g%2); 31 g=0; 32 } 33 else 34 { 35 if(x[i]==1) 36 { 37 for(int j=1;j<=n;++j) 38 a[y[i]][j]=!a[y[i]][j]; 39 } 40 if(x[i]==2) 41 { 42 for(int j=1;j<=n;++j) 43 a[j][y[i]]=!a[j][y[i]]; 44 } 45 } 46 } 47 return 0; 48 }
能过三个点,其余都会T。
不过正解,,好难想啊。。
正解思路:
输入的时候是这样的,然后可以手动模拟一下样例,,找找规律。。
也许就找到了呢。
看题目,题目中要输出所求g%2,
任何一个正整数,%2后要么等于1,要么等于0,就这两种情况。
然后看要求的g的算数过程,
是所有a[i][j]*a[j][i]的和,不难发现,除了行列相同时,也就是i==j时,其余所有的乘积都被加了两遍。
那么除了对角线的话,
我说的对角线只有这一条
除了这个别的都加了两遍意味着什么?
输入的这个矩阵中的元素要么是1,要么是0,
那他们两两之间的乘积也是要么是1,要么是0,
所以当i!=j的时候,其余所有要求的乘积相加一定是个偶数,
(因为都会加两遍嘛,要么1+1,要么0+0,那这些两遍的和再相加就一定是偶数)。
所以不看对角线的话,g%2一定=0,
所以就直接不用管这些了,只看对角线,
刚开始输入的时候对角线元素如果出现1,ans就取反,(初始为0)
(然后这应该也是个规律吧。。。暂且不讨论这个)
在下面q个操作中,有行取反的,也有列取反的,
但无论是行取反,还是列取反,一次操作只会改变一次对角线上的一个值。(important)
所以不管怎么着,只要出现取反操作,ans直接跟着取反就行了,
然后要输出的时候,就输出ans。
这种题边输入边输出也是可以的。
还不理解可以结合代码,模拟样例来看。
ac代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 8 int n,q,t,x,y,ans; 9 10 int main() 11 { 12 scanf("%d%d",&n,&q); 13 for(int i=1;i<=n;++i) 14 for(int j=1;j<=n;++j) 15 { 16 scanf("%d",&t); 17 if(i==j&&t) ans=!ans; 18 } 19 for(int i=1;i<=q;++i) 20 { 21 scanf("%d",&x); 22 if(x!=3) 23 { 24 scanf("%d",&y); 25 ans=!ans; 26 } 27 else 28 printf("%d",ans); 29 } 30 return 0; 31 }
我的表达可能有些不清,
看不懂的话,可以看一下这个blog:
http://www.cnblogs.com/cangT-Tlan/p/8017982.html