题意简介
\qquad 意思就是有 T T T组数据,每组数据中有 n n n个数,分别为 a 1 , a 2 , a 3 . . . a n a_{1},a_{2},a_{3}...a_{n} a1,a2,a3...an。从这n个数中任选一个或多个数使得所取出来的数的乘积为完全平方数,问有多少种取法。
\qquad 其中 1 ≤ T ≤ 30 , 1 ≤ N ≤ 100 , 1 ≤ a i ≤ 1 0 15 1 \leq T\leq 30,1 \leq N\leq 100,1 \leq a_{i}\leq 10^{15} 1≤T≤30,1≤N≤100,1≤ai≤1015并且每个数不包含大于 500 500 500的质因子
思路
\qquad
既然题目告诉我们每个数不含有大于
500
500
500的质因子,那么便从这一点下手。
\qquad
我们不妨以
{
4
,
6
,
10
,
15
}
\{4,6,10,15\}
{4,6,10,15}为例。首先我们知道完全平方数里的质因子都是成对出现的,先将四个数分解质因数。
\qquad
4
=
2
2
6
=
2
∗
3
10
=
2
∗
5
15
=
3
∗
5
4=2^2\quad6=2* 3\quad 10=2* 5\quad 15=3* 5
4=226=2∗310=2∗515=3∗5
\qquad
从中我们可以知道这四个数中最大的质数是第三个质数
\qquad
那么我们可以由此列一个异或方程组:
表示2出现次数: ( 0 x o r X 1 ) x o r ( 1 x o r X 2 ) x o r ( 1 x o r X 3 ) x o r ( 0 x o r X 4 ) ≡ 0 ( m o d 2 ) (0xor X_{1})xor(1xorX_{2})xor(1xorX_{3})xor(0xorX_{4})\equiv0(mod\quad2) (0xorX1)xor(1xorX2)xor(1xorX3)xor(0xorX4)≡0(mod2)
表示3出现次数: ( 0 x o r X 1 ) x o r ( 1 x o r X 2 ) x o r ( 0 x o r X 3 ) x o r ( 1 x o r X 4 ) ≡ 0 ( m o d 2 ) (0xor X_{1})xor(1xorX_{2})xor(0xorX_{3})xor(1xorX_{4})\equiv0(mod\quad2) (0xorX1)xor(1xorX2)xor(0xorX3)xor(1xorX4)≡0(mod2)
表示5出现次数: ( 0 x o r X 1 ) x o r ( 0 x o r X 2 ) x o r ( 1 x o r X 3 ) x o r ( 1 x o r X 4 ) ≡ 0 ( m o d 2 ) (0xor X_{1})xor(0xorX_{2})xor(1xorX_{3})xor(1xorX_{4})\equiv0(mod\quad2) (0xorX1)xor(0xorX2)xor(1xorX3)xor(1xorX4)≡0(mod2)
\qquad 其中 X 1 , X 2 . . . X_{1},X_{2}... X1,X2...表示这个数取或不取,取则为 1 1 1,不取则为 0 0 0。
\qquad 通过高斯消元我们就能找出这个方程中有 s s s个自由元,答案就是 2 s − 1 2^{s}-1 2s−1
\qquad 由于题目要求ull自然溢出,所以设置ans的变量时注意一下就好了。
不了解异或方程组的童鞋请戳这里:http://www.cppblog.com/MatoNo1/archive/2012/05/20/175404.html
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int p=1e9+7;
bitset<505>f[505];//加快速率用bitset
ll n;
ll prime[505],h[505],num,s;
void pre() {
for(int i=2; i<=500; i++) {
if(!h[i])prime[++num]=i;
for(int j=1; prime[j]*i<501; j++) {
h[ prime[j]*i ]=1;
if(!(i%prime[j]))break;
}
}
}
void solve() {
scanf("%lld",&n);
memset(f,0,sizeof(f));
ll maxn=-1e9;//记录最大的素数是第几个
ll x;
for(int i=1; i<=n; i++) {
scanf("%lld",&x);
for(int j=1; prime[j]<=x&&j<=num; j++) {
int k=prime[j];
if(!(x%k)) {
if(j>maxn)maxn=j;
int w=0;
while(!(x%k)) {
w^=1;
x/=k;
}//确定初始值.
f[j][i]=w;
}
}
}
ll pos=1;
s=0;
for(int i=1; i<=n; i++) {
int w=0;
for(int j=pos; j<=maxn; j++) {
if(f[j][i]) {
if(pos!=j)swap(f[j],f[pos]);
for(int k=1; k<=maxn; k++) {
if(k==pos)continue;
if(f[k][i])f[k]^=f[pos];
}
w=1;
pos++;
break;
}
}
if(!w)s++;//找有多少个自由元
}
unsigned long long ans=1;//自然溢出
for(int i=1; i<=s; i++)ans*=2;//由于s不大所以不用快速幂
printf("%lld\n",ans-1);//最后答案要-1(排除全不选的情况)
}
int main() {
pre();//欧拉筛筛素数.
ll t;
scanf("%lld",&t);
while(t--)solve();
return 0;
}