HDU 5833 Zhu and 772002 高斯消元解异或方程组,求自由元个数,bitset压位

来源:互联网 发布:淘宝上牛仔裤 编辑:程序博客网 时间:2024/06/07 08:46

Zhu and 772002
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1799 Accepted Submission(s): 624

Problem Description
Zhu and 772002 are both good at math. One day, Zhu wants to test the ability of 772002, so he asks 772002 to solve a math problem.

But 772002 has a appointment with his girl friend. So 772002 gives this problem to you.

There are n numbers a1,a2,…,an. The value of the prime factors of each number does not exceed 2000, you can choose at least one number and multiply them, then you can get a number b.

How many different ways of choices can make b is a perfect square number. The answer maybe too large, so you should output the answer modulo by 1000000007.

Input
First line is a positive integer T , represents there are T test cases.

For each test case:

First line includes a number n(1≤n≤300),next line there are n numbers a1,a2,…,an,(1≤ai≤1018).

Output
For the i-th test case , first output Case #i: in a single line.

Then output the answer of i-th test case modulo by 1000000007.

Sample Input

2
3
3 3 4
3
2 2 2

Sample Output

Case #1:
3
Case #2:
3

解题方法: 白书原题,看这位小哥的吧。见这里

//HDU 5833 XOR GUASS#include <bits/stdc++.h>using namespace std;const int maxn = 2010;typedef long long LL;typedef int Matrix[maxn][maxn];const int mod = 1000000007;Matrix A; //A[i][j]就表示第j个数的这个i素数是奇数还是偶数int n, vis[2010], prime[2010];int pre_deal(int m){    memset(vis, 0, sizeof(vis));    int cnt = 0;    for(int i = 2; i < m; i++){        if(!vis[i]){            prime[cnt++] = i;            for(int j = i*i; j < m; j += i){                vis[j] = 1;            }        }    }    return cnt;}LL powmod(LL a, LL n){    LL res = 1;    while(n){        if(n&1) res = res*a%mod;        a = a*a%mod;        n >>= 1;    }    return res;}int xor_guass(int m, int n) //A是异或方程组系数矩阵 返回秩{    int i = 0, j = 0, k, r, u;    while(i < m && j < n){//当前正在处理第i个方程,第j个变量        r = i;        for(int k = i; k < m; k++) if(A[k][j]){r = k; break;}        if(A[r][j]){             if(r != i) for(k = 0; k <= n; k++) swap(A[r][k], A[i][k]);             //消元完成之后第i行的第一个非0列是第j列,且第u>i行的第j列全是0            for(u = i + 1; u < m; u++) if(A[u][j])                for(k = i; k <= n; k++) A[u][k] ^= A[i][k];            i++;        }        j++;    }    return i;}int main(){    int tot = pre_deal(maxn);    int T, ks = 0; scanf("%d", &T); while(T--){        memset(A, 0, sizeof(A));        scanf("%d", &n);        int maxp = 0;        for(int i = 0; i < n; i++){            LL x;            scanf("%lld", &x);            for(int j = 0; j < tot; j++){                while(x % prime[j] == 0){                    maxp = max(maxp, j);                    x /= prime[j];                    A[j][i] ^= 1;                }            }        }        int rr = xor_guass(maxp + 1, n);//秩        printf("Case #%d:\n", ++ks);        printf("%lld\n", powmod(2, n - rr) - 1);    }    return 0;}

当然我们不能这样A了就算了,在大白树上提到了一种bitset优化的方法,即是bitset压位优化。即是把32列合并到一个无符号32位整数中,然后只需要用一次逐位异或xor就可以处理32列了,所以复杂度可以降到O(n*n*n/32),扣扣常数还是非常支持的。

//HDU 5833 XOR GUASS bitset#include <bits/stdc++.h>using namespace std;const int maxn = 2005;const int mod = 1e9+7;int n, vis[maxn], prime[maxn], cnt;void pre_deal(){    for(int i = 2; i < maxn; i++){        if(vis[i]) continue;        prime[cnt++] = i;        for(int j = i; j < maxn; j += i) vis[j] = 1;    }}bitset <330> A[305]; //A[i][j]就表示第j个数的这个i素数是奇数还是偶数int main(){    pre_deal();    int T, ks = 0; scanf("%d", &T);    while(T--){        printf("Case #%d:\n", ++ks);        for(int i = 0; i < 305; i++) A[i].reset();        scanf("%d", &n);        for(int i = 0; i < n; i++){            long long x;            scanf("%lld", &x);            for(int j = 0; j < cnt; j++){                if(x%prime[j] == 0){                    int flag = 0;                    while(x%prime[j] == 0){                        x /= prime[j];                        flag ^= 1;                    }                    A[j][i] = flag;                }            }        }        int i = 0, j = 0; //xor消元之后j就是秩        for(i = 0; i < n; i++){            int id = -1;            for(int k = j; k < cnt; k++){                if(A[k][i]){                    id = k;                    break;                }            }            if(id == -1) continue;            swap(A[j], A[id]);            for(int k = j + 1; k < cnt; k++){                if(A[k][i]) A[k] ^= A[j];            }            j++;        }        int ans = 1;        for(int i = 0; i < n - j; i++) ans = ans * 2 % mod;        ans--;        printf("%d\n", ans);    }    return 0;}

所以一下午只写了2个高斯消元??效率需要挺高啦。

0 0