hdu5833 Zhu and 772002

来源:互联网 发布:淘宝香火符咒西极飞飞 编辑:程序博客网 时间:2024/06/05 04:04

题目大意:从n个数a1,a2,…,an里选出若干个数(至少选一个),然后把选出的数乘起来得到b,问b是完全平方数的取数方法有多少种。每个数的质因子不超过2000,答案模上1000000007。
这道题目和POJ1830开关问题类似。首先,n个数中每个数都有取与不取两种操作,令向量x⃗ T=(x1,x2,,xn),其中xi表示是否取第i个数,0表示不取,1表示取。现在我们要判断操作是否合法(即取出的数的积为完全平方数)。不难发现,完全平方数的相同质因子的指数总是偶数,判断若干个数的积是否为完全平方数就看那些数对应的相同质因子的指数的和是否为偶数。若令fij表示第j个数的第i个质因子的指数,则nj=1fijxj表示取出的数的第i个质因子的指数之和(或者说取出的数的乘积的第i个质因子的指数),显然,当所有的质因子的指数均为偶数时,取出的数的的积为完全平方数,即方程组nj=1fijxjmod2=0,题目问的是可行方案数,也就是解的个数,由于是否取模只影响解的值,不影响解的个数,问题转换为求齐次线性方程组Fx⃗ =0的解的个数。由于仅01两种取值,解的个数等于2r,其中r表示解向量中自由变元的个数。题目中说至少取一个数,故零解不合法,最终答案为2r1
题目中说质因子的大小不会超过2000,分解质因子可行,对每个数分解质因子即可得到矩阵F。由于我们只关心质因子指数的奇偶性,可将每个元素都模2(或者说将原始方程组里的mod2放到fij后面),将其变成01矩阵,提高数值稳定性。实际上,由于“模2加”等价于异或,程序中均用异或来代替。

#include<iostream>#include<algorithm>#include<cmath>#include<cstring>using namespace std;typedef unsigned long long ull;const int maxn = 2001, mod = 1000000007;bool isnpri[maxn];int prime[maxn], k;inline void getPrime(){    for (int i = 2; i < maxn; i++)    {        if (!isnpri[i]) prime[k++] = i;        for (int j = 0; j < k && i*prime[j] < maxn; j++)        {            isnpri[i*prime[j]] = true;            if (i%prime[j] == 0)    break;        }    }}ull a[300];int fac[maxn][300];inline void factor(int n){    ull now = a[n];    for (int i = 0; i < k; i++)        while (now%prime[i] == 0)            fac[i][n] ^= 1, now /= prime[i];}inline int gauss(int n){    int i = 0, j = 0;    while (j < n)    {        int id = i;        for (int k = i; k < ::k; k++)            if (abs(fac[k][j])) id = k;        if (id != i)        {            for (int k = j; k < n; k++)                swap(fac[i][k], fac[id][k]);        }        if (fac[i][j] == 0) { j++; continue; }        for (int k = i + 1; k < ::k; k++)        {            if (fac[k][j] == 0) continue;            for (int l = j; l < n; l++)                fac[k][l] ^= fac[i][l];        }        i++, j++;    }    return n - i;}inline ull pow_mod(ull x, ull n){    ull ret = 1;    while (n)    {        if (n & 1)            ret = ret*x%mod;        x = x*x%mod;        n >>= 1;    }    return ret;}int main(){    getPrime();  //筛出2000内的素数    int T, t = 0;    cin >> T;    while (T--)    {        memset(fac, 0, sizeof(fac));        int n;        cin >> n;        for (int i = 0; i < n; i++)        {            cin >> a[i];            factor(i);    //分解质因数        }        int free_element = gauss(n);        ull ans = pow_mod(2, free_element) - 1;        cout << "Case #" << ++t << ":\n";        cout << ans << endl;    }    return 0;}
0 0
原创粉丝点击