zoukankan      html  css  js  c++  java
  • yww 与连通块计数

    yww 与连通块计数

    分析

    观察题目的额外限制,\(s1 | a_i ,a_i| s2\)\(\nexists i>1 ,i^2|s2\)

    这意味着对于\(s2\)的每个因数,出现次数为\(1\)

    如果把\(a_i,s1,s2\)全部除去\(s1\),那么按照剩下所有因数给\(a_i\)标记一个二进制状态\(C_i\)

    那么在选择的联通块里,已经满足条件的因数集合所有的\(\{C_u \ xor \ C_v|(u,v)\in E,u \in V',v\in V'\}\)的或

    有:如果出现\(C_u\)\(C_v\)的某一位不同\(\Leftrightarrow\)这个因数已经出现了\(0,1\)两种情况,即同时满足了\(\text{GCD}\)\(\text{LCM}\)的限制

    因为如果同时出现0,1,必然存在两个相邻点不同

    利用这个性质,我们只用考虑联通块相邻两个点不同的状态

    这时候我们有两种办法计算(个人推荐Solution2哈)

    \(n\)的质因子集合为\(p\)

    Solution1:FWT

    对于点直接进行\(dp\)转移\(dp[u][S]\)表示当前最高点是\(u\),满足条件的因数集合是\(S\)的方案数

    \(dp[u][i \or j \or (C_u \ xor \ C_v)]=dp[u][i]\cdot dp[v][j]\)

    由于有或的操作,所以可以用高位前缀和/\(FWT\)或卷积

    在没有优化的情况下,两种做法复杂度均为\(O(n|p|2^{|p|})\)

    但是不用每次都\(\text{FWT}\)过去\(\text{FWT}\)回来,所以省去之后复杂度为\(O(n\cdot 2^{|p|})\)

    代码不是我的哈(@神仙Rtx)

    #include <bits/stdc++.h>
    #define rep(i, a, b) for(int i(a), i##_END(b); i <= i##_END; i++)
    #define drep(i, a, b) for(int i(a), i##_END(b); i >= i##_END; i--)
    using namespace std;
    const int maxn = 1010, mod = 1e9+7;
    typedef long long ll;
    vector<int> e[maxn];
    int n, pr[60], cnt, v[60], hs[maxn];
    ll a[maxn], s1, s2, f[maxn][(1<<15)+10], ans[(1<<15)+10];
    inline void ins(ll &x, ll y) { x = (x + y >= mod ? x + y - mod : x + y); }
    
    void init(int N) {
    	rep(i, 2, N) {
    		if(!v[i]) pr[++cnt] = i;
    		for(int j = 1; j <= cnt && i * pr[j] <= N; ++j) 
    			v[i * pr[j]] = 1;
    	}
    }
    void rfwt(ll *p, int N) {
    	for(int mid = 1; mid < N; mid <<= 1) 
    		for(int i = 0; i < N; i += (mid << 1))
    			for(int j = 0; j < mid; ++j) ins(p[i + j + mid], mod - p[i + j]);
    }
    void dfs(int x, int pa) {
    	rep(i, 0, (1<<cnt)-1) f[x][i] = 1; // 意思是f[x][0]=1,手动FWT了
    	rep(i, 0, e[x].size() - 1) if(e[x][i] != pa) {
    		int y = e[x][i];
    		dfs(y, x);
    		int diff = hs[x] ^ hs[y];
    		for(int s = diff; s < (1<<cnt); s = (s+1)|diff) 
    			ins(f[x][s], f[x][s] * f[y][s] % mod); // 枚举diff的父集转移
    	}
    	rep(i, 0, (1<<cnt)-1) ins(ans[i], f[x][i]); 
    }
    int main() {
    	scanf("%d%lld%lld", &n, &s1, &s2), s2 /= s1;
    	int x, y;
    	rep(i, 1, n) scanf("%lld", &a[i]), a[i] /= s1;
    	rep(i, 2, n) scanf("%d%d", &x, &y), e[x].push_back(y), e[y].push_back(x);
    	init(50);
    	rep(i, 1, n) rep(j, 1, cnt) if(a[i] % pr[j] == 0) hs[i] |= (1<<(j-1));
    	dfs(1, 0);
    	rfwt(ans, 1<<cnt); // 最后FWT回来就可以了
    	int mx = 0;
    	rep(i, 1, cnt) if(s2 % pr[i] == 0) mx |= (1<<(i-1));
    	printf("%lld\n", ans[mx]);
    	return 0;
    }
    

    Solution2:容斥

    枚举不满足条件的因数集合为\(S\),那么必然有\((C_u \ xor \ C_v) \and S={\empty}\)

    \(O(n) \ \ \text{dp}\)求解即可和上面一样,但是省去了第二维

    然后就是简单的奇偶容斥了

    可以看到,复杂度就是\(O(n\cdot 2^{|p|})\),跑满的

    const int N=1e3+10;
    
    int n,C[N],fac[N],fc;
    ll A,B,g;
    ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); }
    vector <int> G[N];
    int S;
    ll dp[N];
    
    void dfs(int u,int f) {
    	dp[u]=1;
    	for(int v:G[u]) if(v!=f) {
    		dfs(v,u);
    		if(((C[u]^C[v])&S)==0) dp[u]=(dp[u]+dp[u]*dp[v])%P; // 按照限制dp
    	}
    }
    
    int main(){
    	n=rd(),A=rd<ll>(),B=rd<ll>(),B/=A;
    	rep(i,2,50) if(B%i==0) B/=i,fac[fc++]=i; // 这些是预处理因数集合
    	rep(i,1,n) {
    		ll x=rd<ll>()/A;
    		rep(j,0,fc-1) if(x%fac[j]==0) C[i]|=1<<j;
    	}
            A=1;
    	rep(i,2,n) {
    		int u=rd(),v=rd();
    		G[u].pb(v),G[v].pb(u);
    	}
    	ll ans=0;
    	for(S=0;S<(1<<fc);++S) { // 枚举不合法的状态
    		int cnt=0;
    		rep(i,0,fc-1) if(S&(1<<i)) cnt^=1;
    		dfs(1,0);
    		rep(i,1,n) if(cnt) ans-=dp[i];
    				else ans+=dp[i]; // 偶加奇减
    	}
    	ans=(ans%P+P)%P;
    	printf("%lld\n",ans);
    }
    
  • 相关阅读:
    PAT 甲级 1115 Counting Nodes in a BST (30 分)
    PAT 甲级 1114 Family Property (25 分)
    PAT 甲级 1114 Family Property (25 分)
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12743738.html
Copyright © 2011-2022 走看看