题目链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4840
The lottery BWS is played annually. In this lottery N people bet choosing K numbers each. In aformal way, we can say that Bij is the j-th value bet by the i-th person. Then the organizers chooseK positive integers. The chosen numbers are called W1, W2, . . . , WK.
The winners are calculated as followed:
• A non-empty subset is chosen randomly from the N participants; in other words, some participantsare luckily chosen.
• For each person in this subset the value S1 is calculated, the sum of all the first numbers bet bythem, that is, the sum of the Bi1 where i is the index of each chosen person. In the same waythe values S2, . . . , SK are calculated.
• A parity test between Wj and Sj is performed; in other words, it is verified if the parity (if anumber is pair or odd) matches between W1 and S1, W2 and S2, and so on until WK and SK.
• If all parities match, then the people in this subset are considered the winners!The organizers want to know: is it possible to pick the numbers W1, W2, . . . , WK so that there is nosubset of winning participants?
Input
The input contains several test cases. The first line of a test case contains the numbers N (1 ≤N ≤ 30000) and K (3 ≤ K ≤ 50), which represent the number of participants and the quantity ofnumbers bet by each person, respectively. The participants bet with integer numbers between 1 and109, inclusive. Each of the next N lines contains K numbers representing the bet of each person, oneperson per line.
Output
For each test case in the input you must output a single line, containing one letter: ‘S’ in case it ispossible or ‘N’ otherwise.
Sample Input
2 3
1 2 3
5 6 7
3 3
3 2 1
6 5 4
4 4 4
4 3
9 4 7
4 4 4
2 7 2
2 2 1
Sample Output
S
S
N
---------------------------------------------------------分割线------------------------------------------------------------
这个题目说,选择任意x行相加,共有2^N-1种可能,问是否存在一个序列。和所有的可能,至少存一个数,然后他们奇偶不同。
其实我们可以这么想,我们把加起来的数都对2取余,这样的话偶数就为0,奇数为1,这样我们就可以把每一行看成一个数了,那么不符合的条件无论我们怎么写,都存在一个数和我们写的数是一样的。
由于我们的写法有2^k种可能,所以对于N<=k的,我们绝对能写出一个数和不等于其中的任意的数。
下面我们讨论关于k<N的情况:
然后我们再考虑一个东西:奇+奇=偶数,奇+偶=奇,偶+偶=偶。这个是个很好的性质。它和异或是一样的。
所以把相加变成异或,这个有什么用呢?其实是因为异或的一个性质,x^x=0。也就是说,我们通过多步异或之后,可以换成0次或者1次,也就是取或者不取。
然后我们就可以用矩阵了。为什么用矩阵?其实是这样的。假设我前k行能够搞出一个上三角阵或者单位阵的话,那么我上面异或就可以得到1到2^k-1所有数,而我们现在是k<N。也就是说除却k行之外,还有其他的行,用其中任意一个和上面的若干个异或,又可以得到0,也就是说2^k种可能都可以表示出来。
-------------------------------------------------分割线-------------------------------------------------------------------
总结:
对于k>=N的情况,直接就是S;
对于k<N的情况,高斯消元之后看看前k行对角线是否都为1,如果是的话,那么就是N,否则就是S。
#include<cstdio>
#include<algorithm>
using namespace std;
int num[40000][60];
bool Guss(int n,int r)
{
if(r>=n)
return false;
for(int i=0; i<r; i++) {
for(int j=i; j<n; j++) {
if(num[j][i]) {
for(int k=0; k<r; k++)
swap(num[i][k],num[j][k]);
break;
}
}
for(int j=i+1; j<n; j++) {
if(num[j][i])
for(int k=0; k<r; k++) {
num[j][k]^=num[i][k];
}
}
}
int xx=min(n,r);
for(int i=0; i<xx; i++)
if(!num[i][i])
return false;
return true;
}
int main()
{
int n,k;
while(scanf("%d%d",&n,&k)!=EOF) {
for(int i=0; i<n; i++) {
for(int j=0; j<k; j++) {
scanf("%d",&num[i][j]);
num[i][j]&=1;
}
}
int x=Guss(n,k);
if(x)
printf("N\n");
else
printf("S\n");
}
return 0;
}