Zhu and 772002 HDU - 5833 (高斯消元求異或方程組解的個數)

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5833

題目描述:給定n個數,每個數所含質因子最大不超過2000,選取任意個(至少爲1個)數字相乘,要求所得乘積爲完全平方數,求共有多少種選取方案。

思路:題目都已經說每個數所含最大質因子不超過2000了,很明顯是要分解質因子求解,求的2000以內的素數共303個。要想相乘組成完全平方數,只要所選取的x個數中含有的質因子都是偶數個都行,奇偶可以用10表示,1爲奇數個,0爲偶數個。首先需要求出每個數所含質因子及其個數,設a[i][j]表示第j個數所含質因子i的個數,0表示偶數個,1表示奇數個。x[i]表示是否選取第i個數。則只需:

a[1][1] *x[1] ^ a[1][2] * x[2] ^ ...... ^ a[1][n] * x[n] = 0

a[2][1] *x[1] ^ a[2][2] * x[2] ^ ...... ^ a[2][n] * x[n] = 0

...........

a[n][1] *x[1] ^ a[n][2] * x[2] ^ ...... ^ a[n][n] * x[n] = 0

這樣很明顯用高斯消元求矩陣的秩,進而求出自由變量的個數ans,那麼方程組X[i]的解的個數爲2^ans,注意要減去一個數都不選(即X[i]全爲0的情況),故答案爲2^ans-1。

代碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<sstream>
#include<deque>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int  maxn = 2000 + 10;
const int  maxt = 300 + 10;
const int mod = 10;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
const int Dis[] = {-1, 1, -5, 5};
const int inf = 0x3f3f3f3f;
const int MOD = 1000000007;
ll n, m, k;
int prime[500];//素數表
bool vis[maxn];
int a[maxn][maxn];//a[i][j]表示數字j中含有所含質因子i的個數,奇數個爲1,偶數個爲0
ll num[maxn];
int cnt;
void getPrime(){//2000以內素數打表
    memset(prime, 0, sizeof prime);
    memset(vis, false, sizeof vis);
    int maxnum = 2000;
    cnt = 0;
    for(int i = 2; i <= maxnum; ++i)if(!vis[i]){
        prime[++cnt] = i;
        vis[i] = true;
        for(int j = i * i; j <= maxnum; j += i){
            vis[j] = true;
        }
    }
}
ll Gauss(){//高斯消元
    int i, j, k, x, y;
    for(i = 1, j = 1; i <= cnt && j <= n; ++j){
        k = i;
        while(k <= cnt && !a[k][j]) ++k;
        if(a[k][j]){
            swap(a[i], a[k]);
            for(x = i + 1; x <= cnt; ++x){
                if(a[x][j]){
                    for(y = i; y <= n; ++y){
                        a[x][y] ^= a[i][y];
                    }
                }
            }
            ++i;
        }
    }
    return (ll)n - (ll)i + 1ll;//自由變量的個數,每個自由變量可以爲0也可以爲1,故解的個數就是(1<<自由變量個數)
}
ll quick_pow(ll a, ll x){//快速冪
    ll ans = 1;
    while(x > 0){
        if(x & 1) ans = (ans * a) % MOD;
        x >>= 1;
        a = (a * a) % MOD;
    }
    return ans;
}
int main(){
    getPrime();
    int t, kase = 0;
    scanf("%d", &t);
    while(t--){
        scanf("%I64d", &n);
        ll tmp;
        memset(a, 0, sizeof a);
        for(int i = 1; i <= n; ++i){
            scanf("%lld", &num[i]);
            tmp = num[i];
            for(int j = 1; j <= cnt; ++j){//求每個數所含質因子及其個數
                if(tmp % prime[j] == 0){
                     while(tmp > 0 && tmp % prime[j] == 0){
                        a[j][i] ^= 1;//異或判斷有奇數個還是偶數個
                        tmp /= prime[j];
                    }
                }
            }
        }
        ll x = Gauss();
        printf("Case #%d:\n", ++kase);
        printf("%lld\n", quick_pow(2, x) - 1);//減去全爲0(也就是一個數都不選)的情況
    }
    return 0;
}

/*

2
3
3 3 4
3
2 2 2

*/


a[i][1] *x[1] ^ a[i][2] * x[2] ^ ...... ^ a[i][n] * x[n] = 0
a[i][1] *x[1] ^ a[i][2] * x[2] ^ ...... ^ a[i][n] * x[n] = 0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章