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
  • 相关阅读:
    前沿技术解密——VirtualDOM
    Ques核心思想——CSS Namespace
    Unix Pipes to Javascript Pipes
    Road to the future——伪MVVM库Q.js
    聊聊CSS postproccessors
    【译】十款性能最佳的压缩算法
    Kafka Streams开发入门(9)
    Kafka Streams开发入门(8)
    【译】Kafka Producer Sticky Partitioner
    【译】99th Percentile Latency at Scale with Apache Kafka
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14402286.html
Copyright © 2011-2022 走看看