poj1830:开关问题
链接:http://poj.org/problem?id=1830
某天“佐理慧学姐”突然来问了我这道题。
诶,窝只会线性基,但是好像搞不了方案数啊……
啃题解吧。
woc!线性代数哦,就是那种我不会的东西么。
矩阵的秩是啥啊……自由元又是啥啊……
没办法,开始补一波线性代数。
看到一半跑出来A掉了这题。
矩阵的秩啊……可以理解为给你一些线性方程组,然后你会发现x+y=1其实跟2x+2y=2是一样的,那这俩玩意其实就是一个方程,矩阵的秩就是最后真正有用的方程数量。
自由元啊……就是解到最后发现有些变量可以随便取咯……
然后本题答案就是$2^{自由元个数}$
如果我完全不会线性代数怎么理解这题嘞?
我先找到可以让第一个位置灯状态变化的操作,然后强行钦定内定就由你来点亮这盏灯,把后面可以点亮这盏灯的都异或上它,相当于如果用了那盏灯就再把现在这盏撤销掉,然后异或过的灯就变成两盏灯的组合,然后一直做下去,每个操作就都变成很多操作的组合惹……
最后看下有哪些组合是可有可无的就吼了。
由于行秩和列秩素一样的,所以你在码的时候……把行和列倒过来了也没关系……
#include<cstring> #include<cstdio> #include<algorithm> #define MN 200001 using namespace std; int read_p,read_ca,read_f; inline int read(){ read_p=0;read_ca=getchar();read_f=1; while(read_ca<'0'||read_ca>'9') read_f=read_ca=='-'?-1:read_f,read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p*read_f; } int T,n,m,A,B,MMH; bool o[40],e[40],a[40][40]; int work(){ int i,j,k,l; for (i=j=0;j<n;j++){ for (k=i;k<n;k++) if (a[k][j]) break; if (k<n){ for (l=j;l<=n;l++) swap(a[i][l],a[k][l]); for (l=i+1;l<=n;l++) if (a[l][j]) for (k=j;k<=n;k++) a[l][k]^=a[i][k]; i++; } } for (j=i;j<n;j++) if (a[j][n]) return -1; return 1<<(n-i); } int main(){ register int i; T=read(); while (T--){ n=read();memset(a,0,sizeof(a)); for (i=0;i<n;i++) o[i]=read(); for (i=0;i<n;a[i][i]=1,i++) if (read()!=o[i]) a[i][n]=1; while ((A=read())|(B=read())) a[B-1][A-1]=1; MMH=work(); if (MMH==-1) puts("Oh,it's impossible~!!");else printf("%d\n",MMH); } }