zoukankan      html  css  js  c++  java
  • cf 895C Square Subsets

    传送门

    给出一个序列,找到一个子集,使得子集内的元素乘积是平方数。

    考虑平方数的特点,就是唯一分解定理之后,质因子的幂一定是偶数。

    数字很小,那么质因子肯定是在([1,70])以内的,有(18)个。

    那么就把每个数字用二进制表示,可以用18位的二进制表示,0表示偶数次,1表示奇数次

    那相当于是集合里面的元素任何位的1的个数都是偶数才行。因为两个数字相乘,就是每一个质因子表示的位的异或。

    那么我就需要找到一些集合,使得异或和是0就行了。

    那么考虑到线性基的特点,线性基里的数是最少集合使得线性基里的数字异或和是非0。

    假设线性基里的元素个数是(s),那么答案就是非线性基里真子集的个数,就是(2^{n-s}-1)

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int MaxBasis = 20;///二进制位数
    const int mod = 1e9 + 7;
    template<typename T = long long> inline T read() {
        T s = 0, f = 1; char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();} 
        return s * f;
    }
    struct Linear_Basis {
        ll base[MaxBasis + 10]; bool rel; int sz;
        int tim[MaxBasis];
        vector<ll> Basis;/// 线性基(向量)
        Linear_Basis() { memset(base, 0, sizeof(base)); rel = false; sz = 0; Basis.clear();}
        void init() {
            memset(base, 0, sizeof(base)); rel = false; sz = 0; Basis.clear();
            memset(tim, 0, sizeof(tim));
        }
        bool add(ll x) { //加入线性基中
            for (int i = MaxBasis; i >= 0; --i) {
                if (!(x >> i & 1)) continue;
                if (base[i]) {x ^= base[i];}
                else {
                    base[i] = x, ++sz;
                    return 1;
                }
            }
            rel = true;
            return 0;
        }
        ll Max(ll ans = 0) { //取最大
            for(int i = MaxBasis; i >= 0; i--) 
                if(!(ans >> i & 1)) ans ^= base[i];
            return ans;
        }
        ll Min(ll ans = 0) { //取最小
            for(int i = 0; i <= MaxBasis; i++) ans = min(ans, ans ^ base[i]);
            return ans;
        }
        void GetBasis() { //构造向量,用于之后求第k小
            for (int i = 0; i <= MaxBasis; ++i)
                if (base[i]) Basis.push_back(base[i]);
        }
        void bin(struct Linear_Basis &b) { // 线性基求并(合并)
            for(int i = 0;i <= MaxBasis; i++) if(b.base[i]) add(b.base[i]);
        }
        Linear_Basis jiao(Linear_Basis a,Linear_Basis b){ // 线性基求交
            Linear_Basis g, tmp = a;
            ll cur, d;
            for(int i = 0;i <= MaxBasis;i++) if(b.base[i]){
                cur = 0,d = b.base[i];
                for(int j = i;j >= 0;j--) if(d>>j&1){
                    if(tmp.base[j]){
                        d ^= tmp.base[j],cur ^= a.base[j];
                        if(d) continue;
                        g.base[i] = cur;
                    }else tmp.base[j] = d, a.base[j] = cur;
                    break;
                }
            }
            return g;
        }
        ll Min_Kth(ll k) { // 线性基中第k小
            if(rel) k--; // 线性基未满存在0
            if(k >= (1ll << sz)) return -1;
            ll ans = 0;
            for(int i = 0; i < sz; i++) if(k & (1ll << i)) ans ^= Basis[i];
            return ans;
        }
    } lb;
    const int N = 5e5 + 5;
    ll a[N];
    ll pow(ll a, ll b, ll p){
        ll ans = 1; a %= p;
        while(b){
            if(b & 1) ans = ans * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return ans;
    }
    int pri[N], id[N], tot;
    bool check(int n) {
        if(n == 1) return 0;
        for(int i = 2; i * i <= n; i++) if(n % i == 0) return 0;
        return 1;
    }
    int main(){
        int n = read();
        for(int i = 1; i <= n; i++) a[i] = read();
        for(int i = 1; i <= 70; i++) if(check(i)) pri[++tot] = i, id[i] = tot;
        for(int i = 1; i <= n; i++) {
            int x = a[i]; a[i] = 0;
            for(int j = 2; j * j <= x; j++) {
                if(x % j == 0) {
                    int num = 0;
                    while(x % j == 0) x /= j, num++;
                    if(num & 1) a[i] |= 1 << id[j];
                }
            }
            if(x > 1) a[i] |= 1 << id[x];
            // cout << a[i] << endl;
        }
        for(int i = 1; i <= n; i++) lb.add(a[i]);
        printf("%lld
    ", (pow(2, n - lb.sz, mod) - 1 + mod) % mod);
        return 0;
    }
    
    I‘m Stein, welcome to my blog
  • 相关阅读:
    iaas,paas,saas理解
    July 06th. 2018, Week 27th. Friday
    July 05th. 2018, Week 27th. Thursday
    July 04th. 2018, Week 27th. Wednesday
    July 03rd. 2018, Week 27th. Tuesday
    July 02nd. 2018, Week 27th. Monday
    July 01st. 2018, Week 27th. Sunday
    June 30th. 2018, Week 26th. Saturday
    June 29th. 2018, Week 26th. Friday
    June 28th. 2018, Week 26th. Thursday
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14402286.html
Copyright © 2011-2022 走看看