51nod 1323 完美平方

来源:互联网 发布:淘宝图片轮播怎么做 编辑:程序博客网 时间:2024/05/21 22:45

题目链接.

异或方程组高斯消元例题。

每个元素选与不选设为未知数。

同一行同一列搞个方程。

至于是完全平方数就分解质因数,对每个质因子建一个方程。

答案是2的自由元个数次幂。

自由元个数=元的个数-有用方程的条数。

其实我到现在才知道高斯消元非三角矩阵的打法,感觉以前学了假的消元。

可以用bitset优化,很简单,这里不讲。

算法竞赛入门经典这本书里有一道类似的题,打法也是从那里copy的。

Code:

#include<set>#include<cstdio>#include<algorithm>#define fo(i, x, y) for(int i = x; i <= y; i ++)#define min(a, b) ((a) < (b) ? (a) : (b))using namespace std;const int N = 21, mo = 1e9 + 7;const int M = 1e5;int T;int p[M], bz[M];int n, a[N][N], num[N][N];int u[N][N][20], v[N][N][20];int b[N * 100][N * N], tot;set<int> s;int ans = 1;void Build() {    fo(i, 2, M)  {        if(!bz[i]) p[++ p[0]] = i;        fo(j, 1, p[0]) {            int k = i * p[j];            if(k > M) break;            bz[k] = 1;            if(i % p[j] == 0) break;        }    }}void Clear() {    fo(i, 1, tot) fo(j, 0, n * n) b[i][j] = 0;    tot = 0;}void Built() {    scanf("%d", &n);    fo(i, 1, n) fo(j, 1, n) num[i][j] = (i - 1) * n + j;    fo(i, 1, n) {        b[++ tot][0] = 1;        fo(j, 1, n) b[tot][num[i][j]] = 1;    }    fo(j, 1, n) {        b[++ tot][0] = 1;        fo(i, 1, n) b[tot][num[i][j]] = 1;    }    fo(i, 1, n) fo(j, 1, n) scanf("%d", &a[i][j]);    fo(i, 1, n) {        fo(j, 1, n) {            int x = a[i][j]; u[i][j][0] = 0;            for(int k = 1; k <= p[0] && p[k] * p[k] <= x; k ++)                if(x % p[k] == 0) {                    u[i][j][++ u[i][j][0]] = p[k];                    v[i][j][u[i][j][0]] = 0;                    while(x % p[k] == 0)                        v[i][j][u[i][j][0]] ++, x /= p[k];                }            if(x > 1) u[i][j][++ u[i][j][0]] = x, v[i][j][u[i][j][0]] = 1;            fo(k, 1, u[i][j][0]) s.insert(u[i][j][k]);        }    }    while(!s.empty()) {        int x = *s.begin(); s.erase(x);        b[++ tot][0] = 0;        fo(i, 1, n) {            fo(j, 1, n) {                fo(k, 1, u[i][j][0]) if(u[i][j][k] == x && v[i][j][k] % 2)                    b[tot][num[i][j]] = 1;            }        }    }}void W() {    fo(i, 1, tot) {        fo(j, 0, n * n) printf("%d ", b[i][j]);        printf("\n");    }    printf("\n");}int Solve(int m, int n) {    int i = 1, j = 1;    while(i <= m && j <= n) {        int r = i;        fo(k, i, m) if(b[k][j]) r = k;        if(b[r][j]) {            fo(k, 0, n) swap(b[i][k], b[r][k]);            fo(u, i + 1, m) if(b[u][j])                fo(k, 0, n) b[u][k] ^= b[i][k];            i ++;           }        j ++;    }    return n - i + 1;}void pd() {    fo(i, 1, tot) {        int bz = 1;        fo(j, 1, n * n) if(b[i][j]) {            bz = 0; break;        }        if(bz && b[i][0]) {            ans = 0; return;        }    }}int main() {    Build();    for(scanf("%d", &T); T; T --) {        Clear();        Built();        int r = Solve(tot, n * n);        ans = 1; fo(i, 1, r) ans = (ans * 2) % mo;        pd(); printf("%d\n", ans);    }}