zoukankan      html  css  js  c++  java
  • CF724G. Xor-matic Number of the Graph

    题意

    http://codeforces.com/contest/724/problem/G
    定义三元组((u,v,s)(u<v))(u)(v)的路径的(xor)和为(s)(可以不是简单路径),((u,v,s))不同当且仅当(u,v,s)的其中一个参数不同。
    求所有不同三元组的(s)值之和。
    (n in [1,10^5],min [0, 2cdot 10^5], win [0,10^{18}])

    题解

    显然在同个联通块中,当前联通块中的所有环都可以被取到。而且每一条路径一定是一条简单路径与若干个环的(xor)和组成。
    环的部分可以利用线性基来统计可以组成的不同的(xor)值个数。
    (dfs)出搜索树,做树上前缀和,那么一条简单路径的(xor)和就是(s[u] oplus s[v]),并顺便处理出所有环的(xor)和扔进线性基里。
    因为(xor)对各位互不影响所以考虑按位处理。
    对于第(k)位,将(s)划分为第(k)位为(0)和为(1)的,数量记为(c_0)(c_1)
    可以划分为(3)种情况:

    • (0 oplus 0),共(frac{c_0 imes (c_0-1)}{2})种。
    • (1 oplus 1),共(frac{c_1 imes (c_1-1)}{2})种。
    • (1 oplus 0),共(c_0 imes c_1)种。

    同时线性基中也有第(k)位为(0)和第(k)位为(1)的两种情况。
    几种情况分别组合一下就好。
    设线性基为(b)。则有

    • (b[k]=0)时,对于情况三,贡献的不同(xor)和为(2^{|b|})种。对于情况一和情况二,贡献为(0)
    • (b[k]=1)时,对于情况三,贡献的不同(xor)和为(2^{|b|-1})种。对于情况一和情况二,贡献为(2^{|b|-1})种。

    复杂度为(O(n log^2 max(w_i)))

    #include <bits/stdc++.h>
    using namespace std;
    
    namespace io {
    char buf[1<<21], *p1 = buf, *p2 = buf, buf1[1<<21];
    inline char gc() {
        if(p1 != p2) return *p1++;
        p1 = buf;
        p2 = p1 + fread(buf, 1, 1 << 21, stdin);
        return p1 == p2 ? EOF : *p1++;
    }
    #define G gc
    
    #ifndef ONLINE_JUDGE
    #undef G
    #define G getchar
    #endif
    
    template<class I>
    inline void read(I &x) {
        x = 0; I f = 1; char c = G();
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = G(); }
        while(c >= '0' && c <= '9') {x = x * 10LL + c - '0'; c = G(); }
        x *= f;
    }
    
    template<class I>
    inline void write(I x) {
        if(x == 0) {putchar('0'); return;}
        I tmp = x > 0 ? x : -x;
        if(x < 0) putchar('-');
        int cnt = 0;
        while(tmp > 0) {
            buf1[cnt++] = tmp % 10 + '0';
            tmp /= 10;
        }
        while(cnt > 0) putchar(buf1[--cnt]);
    }
    
    #define in(x) read(x)
    #define outn(x) write(x), putchar('
    ')
    #define out(x) write(x), putchar(' ')
    
    } using namespace io;
    
    
    #define ll long long
    const int N = 100010;
    const ll mod = 1e9 + 7;
    
    int cnt = 1, head[N];
    struct edge {int to, nxt; ll v;} e[N<<2];
    int n, m, tot;
    ll s[N], b[N], ans, pw[N];
    bool vis[N];
    
    struct lb {
    	
    	ll p[64];
    	vector<ll> a;
    	
    	void clear() {
    		a.clear();
    		memset(p, 0, sizeof(p));
    	}
    	
    	void insert(ll x) {
    		for(ll i = 63; i >= 0; --i) 
    			if((x >> i) & 1LL) {
    				if(p[i]) x ^= p[i];
    				else {
    					p[i] = x;
    					return;
    				}
    			}
    	}
    	
    	void init() {
    		for(int i = 0; i <= 63; ++i) {
    			if(p[i])
    			for(int j = i - 1; j >= 0; --j) {
    				if((p[j] >> i) & 1) p[i] ^= p[j];
    			}
    		}
    		for(int i = 0; i <= 63; ++i) 
    			if(p[i]) a.push_back(p[i]);
    	}
    	
    	ll solve(ll k, ll c, ll v) {
    		bool flag = 0; v %= mod;
    		for(int i = 0; i < (int)a.size(); ++i) {
    			if((a[i] >> k) & 1) flag = 1;
    		}
    		if(c) {
    			if(flag) return 1LL * pw[(int)a.size() - 1] * v % mod;
    			return 1LL * pw[(int)a.size()] * v % mod;
    		} else {
    			if(flag) return 1LL * pw[(int)a.size() - 1] * v % mod;
    			return 0;
    		}
    	}
    	
    }B;
    
    void ins(int u, int v, ll w) {
    	e[++cnt] = {v, head[u], w};
    	head[u] = cnt;
    }
    
    void dfs(int u, int in_edge) {
    	vis[u] = 1;
    	b[++tot] = s[u];
    	for(int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if(in_edge == (i ^ 1)) continue;
    		if(vis[v]) {
    			B.insert(s[u] ^ s[v] ^ e[i].v);
    			continue;
    		}
    		s[v] = s[u] ^ e[i].v;
    		dfs(v, i);
    	}
    }
    
    ll power(ll x, ll y) { ll ans = 1;
    	while(y) {
    		if(y & 1) ans = ans * x % mod;
    		x = x * x % mod; y >>= 1;
    	} return ans;
    }
    ll inv2 = power(2, mod - 2);
    
    void solve() {
    	ll c[2] = {0, 0};
    	for(ll k = 0; k < 64; ++k) {
    		c[0] = c[1] = 0;
    		for(int i = 1; i <= tot; ++i) c[(b[i] >> k) & 1LL]++;
    		if(c[0]) (ans += B.solve(k, 0, (1LL << k) % mod * c[0] % mod * (c[0] - 1LL) % mod) * inv2 % mod) %= mod;
    		if(c[1]) (ans += B.solve(k, 0, (1LL << k) % mod * c[1] % mod * (c[1] - 1LL) % mod) * inv2 % mod) %= mod;
    		(ans += B.solve(k, 1, (1LL << k) % mod * c[0] % mod * c[1] % mod)) %= mod;
    	}
    }
    
    int main() {
    	read(n); read(m);
    	for(int u, v, i = 1; i <= m; ++i) {
    		ll w;
    		read(u); read(v); read(w);
    		ins(u, v, w), ins(v, u, w);
    	}
    	pw[0] = 1;
    	for(int i = 1; i <= n; ++i) pw[i] = pw[i - 1] * 2LL % mod;
    	for(int i = 1; i <= n; ++i) {
    		if(!vis[i]) {
    			B.clear(); tot = 0; 
    			dfs(i, 0);
    			B.init();
    			solve();
    		}
    	}
    	outn((ans%mod+mod)%mod);
    }
    /*
    10 20
    1 2 0
    4 3 3
    6 8 7
    10 1 4
    3 8 0
    10 7 0
    9 7 9
    7 1 10
    6 7 2
    8 5 10
    4 5 7
    10 4 2
    6 9 10
    6 10 10
    10 5 5
    4 1 4
    9 8 0
    2 3 7
    4 7 4
    3 1 7
    */
    
  • 相关阅读:
    02-04UML类图之--关联关系(Association)
    02-03UML类图之--实现关系(Implementation)
    02-02UML类图之--泛化关系(generalization)
    02-01UML类图之--依赖关系(Dependence)
    01-07.合成复用原则(Composite Reuse Principle)
    01-06.迪米特法则(Demeter Principle)
    算法 - 二叉搜索树的第k个结点
    算法
    InteliJ IDEA社区版 两款插件变身旗舰版
    intelliJ idea自定义代码折叠
  • 原文地址:https://www.cnblogs.com/henry-1202/p/11429038.html
Copyright © 2011-2022 走看看