zoukankan      html  css  js  c++  java
  • CF1554E

    题目

    给你一颗n个结点的树,需要执行n次以下操作:

    • 选择一个未被删除结点u,令(a_u)等于与u相邻未被删除的结点数。
    • 将结点u从树中删除

    也就是说,n次操作完后可以得到一个序列(a={a_1,a_2,...,a_n})。问在所有可能的序列(a)中,满足以下条件:

    • 序列(a)可以由上述n次操作得到
    • (gcd(a_1,...,a_n)=k)

    的序列有多少个?

    输出(k=1,2,...,n)的答案。

    题解

    考虑删点顺序很麻烦,换成考虑边的贡献。对于一条边((u,v)),如果先删除点(u),边对(u)有贡献1;如果先删的是点(v),边对(v)有贡献1。因此,每条边贡献的一种分配对应一种删除操作生成的序列,这也说明所有可能的生成的序列有(2^{n-1})个。

    (f_k)代表有多少生成的序列满足其中每个元素都可以被(k)整数。

    显然,(f_1=2^{n-1})

    对于(k>1),可以用以下方法构造一个方案:

    • 以1为根构造有根树,自底向上构造。
    • 假设(u)的子树的结点都已经分配好满足整除(k),对于和(u)相连的边没被如果没被分配给子结点必然就要分配给(u)结点。假设当前分配给(u)结点的的值为(t)
      • 如果(t)可以被(k)整除,什么完成(u)的分配;
      • 否则只能从(u)和父结点相连的边获得一个贡献,得到(t+1)。如果(t+1)都不能被(k)整除,那么必定无解,否则完成分配。

    从构造方法可得,对于(k>1)(f_k=0或1)

    计算所有(f_k)的时间复杂度为(O(n^2))。又可以发现,对于(k)不整除(n-1)(f_k=0)。因为(sum{a_i}=n-1),如果(k|a_i),那么有(k|n)。所以只需要检查(n)的所有因子即可。故时间复杂度为(O(nsigma_0(n)))

    最后(h_k)为答案,有(h_k=sum_limits{i=1}^{lfloorfrac{n}{k} floor}{mu(i)f_{i cdot k}}),总时间复杂度为(O(nlogn+nsigma_0(n)))

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 3e5 + 10;
    const int M = 998244353;
    const double eps = 1e-5;
    
    vector<int> np[N];
    ll f[N], h[N], val[N];
    
    inline ll qpow(ll a, ll b, ll m) {
    	ll res = 1;
    	while(b) {
    		if(b & 1) res = (res * a) % m;
    		a = (a * a) % m;
    		b = b >> 1;
    	}
    	return res;
    }
    
    bool dfs(int p, int fa, int k) {
    	int d = 0;
    	val[p] = 0;
    	for(int nt : np[p]) {
    		if(nt == fa) continue;
    		if(!dfs(nt, p, k)) return false;
    		d++;
    	}
    	val[p] += d;
    	if(val[p] % k != 0) {
    		if(p == 1 || (val[p] + 1) % k != 0) return false;
    		else {
    			val[fa]--;
    			val[p]++;
    		}
    	}
    	return true;
    }
    
    int pri[N], mu[N], cnt;
    bool isnp[N];
    
    int main() {
    	IOS;
    	mu[1] = 1;
    	for(int i = 2; i < N; i++) {
    		if(!isnp[i]) {
    			pri[cnt++] = i;
    			mu[i] = -1;
    		}
    		for(int j = 0; j < cnt && i * pri[j] < N; j++) {
    			isnp[i * pri[j]] = 1;
    			if(i % pri[j] == 0) {
    				mu[i * pri[j]] = 0;
    				break;
    			}
    			mu[i * pri[j]] = -mu[i];
    		}
    	}
    	int t;
    	cin >> t;
    	while(t--) {
    		int n;
    		cin >> n;
    		for(int i = 1; i <= n; i++) {
    			np[i].clear();
    			f[i] = h[i] = 0;
    		}
    		for(int i = 1; i < n; i++) {
    			int u, v;
    			cin >> u >> v;
    			np[u].push_back(v);
    			np[v].push_back(u);
    		}
    		vector<int> d;
    		for(int i = 1; i * i <= n - 1; i++) {
    			if((n - 1) % i == 0) {
    				d.push_back(i);
    				if((n - 1) / i != i) d.push_back((n - 1) / i);
    			}
    		}
    		f[1] = qpow(2, n - 1, M);
    		for(int i = 1; i < d.size(); i++) {
    			f[d[i]] = dfs(1, 0, d[i]);
    		}
    		for(int i = 1; i <= n; i++) {
    			h[i] = f[i];
    			for(int j = 2; j <= n / i; j++) {
    				h[i] = (h[i] + mu[j] * f[i * j] + M) % M;
    			}
    			cout << h[i] << " 
    "[i == n];
    		}
    	}
    }
    
  • 相关阅读:
    myeclipse-9.0安装svn客户端插件
    jquery中lhgdialog插件(一)
    Jquery之ShowLoading遮罩组件
    git 命令
    org.apache.ibatis.builder.IncompleteElementException: Could not find parameter map
    在线压缩图片网址
    如何在知网下载外文文献
    Linux 常见命令
    在VIM 里面编辑和保存
    vi a.sh ABCD
  • 原文地址:https://www.cnblogs.com/limil/p/15244460.html
Copyright © 2011-2022 走看看