Petya was late for the lesson too. The teacher gave him an additional task. For some array a Petya should find the number of different ways to select non-empty subset of elements from it in such a way that their product is equal to a square of some integer.
Two ways are considered different if sets of indexes of elements chosen by these ways are different.
Since the answer can be very large, you should find the answer modulo 109 + 7.
First line contains one integer n (1 ≤ n ≤ 105) — the number of elements in the array.
Second line contains n integers ai (1 ≤ ai ≤ 70) — the elements of the array.
Print one integer — the number of different ways to choose some elements so that their product is a square of a certain integer modulo 109 + 7.
4 1 1 1 1
15
4 2 2 2 2
7
5 1 2 4 5 8
7
会线性基的话,这题就是5分钟题
不然要想很久+码很久的状压DP,或者卡到比赛结束
题意:
给你n个数,每个数<=70,问有多少个集合,满足集合中所有数相乘是个完全平方数(空集除外)
思路:
很容易想到的是:一个完全平方数分解质因数后所有的因子一定都出现偶数次,而这题的ai<=70
小于70的质数有且只有19个,这样就可以将每个数转成一个长度为19的二进制
第i位为1就说明分解质因数后第i个质数出现了奇数次,为0即出现偶数次,之后再把它转回十进制的另一个数
这样问题就变成了n个数,有多少个集合满足它们异或为0!
求出这n个数的线性基,答案就是2^(n-线性基内数的个数)-1
可以用高斯消元证明
#include<stdio.h>
#define mod 1000000007
#define LL long long
int a[100005], p[21];
int z[21] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};
LL Pow(LL x, int y)
{
LL ans = 1;
while(y)
{
if(y%2)
ans = ans*x%mod;
x = x*x%mod;
y /= 2;
}
return ans;
}
int main(void)
{
int n, i, x, j, now, sum;
scanf("%d", &n);
for(i=1;i<=n;i++)
{
scanf("%d", &x);
for(j=0;j<=18;j++)
{
now = 0;
while(x%z[j]==0)
x /= z[j], now ^= 1;
a[i] |= now*(1<<j);
}
}
for(i=1;i<=n;i++)
{
for(j=18;j>=0;j--)
{
if(a[i]&(1<<j))
{
if(p[j]==0)
{
p[j] = a[i];
break;
}
else
a[i] ^= p[j];
}
}
}
sum = n;
for(j=0;j<=18;j++)
{
if(p[j])
sum--;
}
printf("%lld\n", Pow(2ll, sum)-1);
return 0;
}