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个高斯消元??效率需要挺高啦。