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不需要输出)。

输入输出样例

输入样例#1: 复制
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
输出样例#1: 复制
01001

说明

【数据规模】

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,

所以就直接不用管这些了,只看对角线

刚开始输入的时候对角线元素如果出现1ans取反,(初始为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

原文地址:https://www.cnblogs.com/Mary-Sue/p/9125868.html