Codeforces Round#448 C

题意:n个数,问多少个集合的乘积是完全平方数    (x<70)
题解:
完全平方数的因子一定出现偶数个,那么问题就变成有多少个集合的异或和为0

就转化成用线性基来写

第i位为1就说明分解质因数后第i个质数出现了奇数次,为0即出现偶数次,之后再把它转回十进制的另一个数
这样问题就变成了n个数,有多少个集合满足它们异或为0


设线性基的维数是m,那么从非基的nm个数中取任意和做异或得到的数字,均可以通过线性基表出,故答案为2^(nm)1,减一同样是去掉取空集的方案

#include <bits/stdc++.h>
using namespace std;
int n,m,x;
const int p=1e9+7;
struct L_B{
    long long d[61];
    L_B(){memset(d,0,sizeof(d));}
    bool insert(long long val){
        for (int i=60;i>=0;i--)
            if (val&(1LL<<i)){
                if (!d[i]){
                    d[i]=val;
                    break;
                }
                val^=d[i];
            }
        return val>0;
    }
};
vector<int> Pr;
bool isprime(int x){
    for(int i=2;i<x;i++)
        if(x%i==0) return false;
    return true;
}
//第i位为1就说明分解质因数后第i个质数出现了奇数次,为0即出现偶数次,之后再把它转回十进制的另一个数
int getst(int x){ int st=0; for(int i=0;i<Pr.size();i++) while(x%Pr[i]==0){
      st^=(1<<i),x/=Pr[i];
     }
return st; } int main(){ for(int i=2;i<=70;i++)if(isprime(i)) Pr.push_back(i); scanf("%d",&n); L_B B; int cnt=0; long long ans=1; for(int i=0;i<n;i++){ scanf("%d",&x); if(!B.insert(getst(x))) //如果插入不成功
       ans=(ans*2)%p; } printf("%lld\n",(ans-1+p)%p); return 0; }

猜你喜欢

转载自www.cnblogs.com/amitherblogs/p/12381665.html