CF895C Square Subsets [线性基]

线性基的题…

考虑平方数只和拆解质因子的个数的奇偶性有关系

比如说你 \(4\)\(16\) 的贡献都是一样的。因为

\(4 = 2^2 , 16 = 2^4\)

\(2\)\(4\) 奇偶性相同

然后考虑如何线性基,不难想到,二进制可以表示奇偶性,
所以异或和每一位是0的时候就是一个平方数了。

我们考虑把 线性基的元素设为 \(|S|\)

那么你手头只剩下 \(n-|S|\) 个数字还可以被线性基表示的。

如果可以表示,那么说明了这些 \(2^{n-|S|}-1\) 个子集异或和都可以和线性基拼凑成0

所以目标答案就是 \(2^{n-|S|}-1\)


// by Isaunoya
#include <bits/stdc++.h>
using namespace std;

#define rep(i, x, y) for (register int i = (x); i <= (y); ++i)
#define Rep(i, x, y) for (register int i = (x); i >= (y); --i)
#define int long long

const int _ = 1 << 21;
struct I {
    char fin[_], *p1 = fin, *p2 = fin;
    inline char gc() {
        return (p1 == p2) && (p2 = (p1 = fin) + fread(fin, 1, _, stdin), p1 == p2) ? EOF : *p1++;
    }
    inline I& operator>>(int& x) {
        bool sign = 1;
        char c = 0;
        while (c < 48) ((c = gc()) == 45) && (sign = 0);
        x = (c & 15);
        while ((c = gc()) > 47) x = (x << 1) + (x << 3) + (c & 15);
        x = sign ? x : -x;
        return *this;
    }
    inline I& operator>>(double& x) {
        bool sign = 1;
        char c = 0;
        while (c < 48) ((c = gc()) == 45) && (sign = 0);
        x = (c - 48);
        while ((c = gc()) > 47) x = x * 10 + (c - 48);
        if (c == '.') {
            double d = 1.0;
            while ((c = gc()) > 47) d = d * 0.1, x = x + (d * (c - 48));
        }
        x = sign ? x : -x;
        return *this;
    }
    inline I& operator>>(char& x) {
        do
            x = gc();
        while (isspace(x));
        return *this;
    }
    inline I& operator>>(string& s) {
        s = "";
        char c = gc();
        while (isspace(c)) c = gc();
        while (!isspace(c) && c != EOF) s += c, c = gc();
        return *this;
    }
} in;
struct O {
    char st[100], fout[_];
    signed stk = 0, top = 0;
    inline void flush() {
        fwrite(fout, 1, top, stdout), fflush(stdout), top = 0;
    }
    inline O& operator<<(int x) {
        if (top > (1 << 20)) flush();
        if (x < 0) fout[top++] = 45, x = -x;
        do
            st[++stk] = x % 10 ^ 48, x /= 10;
        while (x);
        while (stk) fout[top++] = st[stk--];
        return *this;
    }
    inline O& operator<<(char x) {
        fout[top++] = x;
        return *this;
    }
    inline O& operator<<(string s) {
        if (top > (1 << 20)) flush();
        for (char x : s) fout[top++] = x;
        return *this;
    }
} out;
#define pb emplace_back
#define fir first
#define sec second

template < class T > inline void cmax(T & x , const T & y) {
    (x < y) && (x = y) ;
}
template < class T > inline void cmin(T & x , const T & y) {
    (x > y) && (x = y) ;
}

int ans = 0 ;
int p[30] ;
int pri[30] = { 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 , 31 , 37 , 41 , 43 , 47 , 53 , 59 , 61 , 67 } ;
void ins(int x) {
    for(int i = 19 ; ~ i ; i --) {
        if(x & (1 << i)) {
            if(! p[i]) {
                p[i] = x ;
            }
            x ^= p[i] ;
        }
    }
}
const int mod = 1e9 + 7 ;
int qpow(int x , int y) {
    int ans = 1 ;
    for( ; y ; y >>= 1 , x = x * x % mod) 
        if(y & 1) ans = ans * x % mod ;
    return ans ;
}
signed main() {
#ifdef _WIN64
    freopen("testdata.in" , "r" , stdin) ;
#endif
    int n ;
    in >> n;
    rep(i , 1 , n) {
        int x ;
        in >> x ;
        int res = 0 ;
        rep(j , 0 , 18) {
            if(x % pri[j] == 0) {
                int now = 0 ; 
                while(x % pri[j] == 0) {
                    x /= pri[j] ;
                    now ^= 1 ;
                }
                res ^= (now << j) ;
            }
        }
        ins(res) ;
    }
    for(int i = 19 ; ~ i ; i --) if(p[i]) n -- ;
    out << ( qpow(2 , n) - 1 ) % mod << '\n' ;
    return out.flush(), 0;
}

猜你喜欢

转载自www.cnblogs.com/Isaunoya/p/12186725.html