xor方程组消元 UVA 11542 Square

 

题目传送门

题意:给n个数,选择一些数字乘积为平方数的选择方案数。训练指南题目。

分析:每一个数字分解质因数。比如4, 6, 10, 15,, 令表示选择第i个数字,那么,如果p是平方数,那么每个质因数上的指数为偶数,x1系数为2已经是偶数不考虑。可以转换为异或为0判断偶数,即奇数置为1,偶数置为0,然后n个数字m个质因数的增广矩阵消元看有几个自由变量(取0或1无所谓),答案是2^r - 1(全部都不取方案不算)

#include <bits/stdc++.h>

const int N = 500 + 5;
bool vis[N];
int prime[N];
int A[N][105];

void sieve(int n) {
    int m = sqrt (n + 0.5);
    for (int i=2; i<=m; ++i) {
        if (!vis[i]) {
            for (int j=i*2; j<=n; j+=i) {
                vis[j] = true;
            }
        }
    }
}

int gen_prime(int n) {
    memset (vis, false, sizeof (vis));
    sieve (n);
    int c = 0;
    for (int i=2; i<=n; ++i) {
        if (!vis[i]) {
            prime[c++] = i;
        }
    }
    return c;
}

int rank(int m, int n) {
    int i = 0, j = 0;
    while (i < m && j < n) {
        int r = i;
        for (int k=i; k<m; ++k) {
            if (A[k][j]) {
                r = k;
                break;
            }
        }
        if (A[r][j]) {
            if (r != i) {
                //!
                for (int k=0; k<=n; ++k) {
                    std::swap (A[r][k], A[i][k]);
                }
            }
            for (int k=i+1; k<m; ++k) {
                if (A[k][j]) {
                    for (int c=i; c<=n; ++c) {
                        A[k][c] ^= A[i][c];
                    }
                }
            }
            ++i;
        }
        ++j;
    }
    return i;
}

//Running_Time
int main() {
    int T; scanf ("%d", &T);
    int m = gen_prime (500);
    while (T--) {
        int n; scanf ("%d", &n);
        memset (A, 0, sizeof (A));
        int maxp = 100;
        for (int i=0; i<n; ++i) {
            long long x; scanf ("%lld", &x);
            for (int j=0; j<m; ++j) {
                while (x % prime[j] == 0) {
                    x /= prime[j];
                    A[j][i] ^= 1;
                    maxp = std::max (maxp, j);
                }
            }
        }
        int r = rank (maxp+1, n);
        std::cout << ((1LL << (n - r)) - 1) << '\n';
    }

    return 0;
}

  

转载于:https://www.cnblogs.com/Running-Time/p/5365681.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值