zoukankan      html  css  js  c++  java
  • 7385. 【2021.11.15NOIP提高组联考】你

    Description

    你是真的强,你是真的强,你是真的强。

    有一颗很强的树,但是没你强,所以这棵树会枯萎。

    这棵树枯萎的时候会产生一个强者序列 \(a\) , 具体的强者序列 \(a\) 生成方式如下:

    • 每次选择一个没有枯萎的点 \(u\), 然后 \(a_{u}\) 等于与 \(u\) 相邻的, 末枯萎的点数。

    • 然后 \(u\) 就会枯萎。

    现在对于每一个 \(k \in[1, n]\) 你要求出合法的强者序列 \(a\) 的数量, 满足 \(g c d\left(a_{1}, a_{2}, a_{3}, a_{4}, \cdots\right)=k\) 答案对 \(998244353\) 取模。

    \(n\le 10^6,\sum n\le 3\times 10^6\)

    Solution

    题目可以转换成对于每条边,指定一个方向,那么 \(a_i\) 就是节点 \(i\) 的入度。那么就有 \(\sum a_i=n-1\)

    \(k>1\) 时,可以证明,答案为 0 或 1。

    证明:由于 \(k>1\),那么叶子节点一定向他的父亲连边,也就是最底层是确定的,因此我们可以逐步向根走,那么整棵树都是确定的,答案非 0 即 1。

    同时由于 \(\sum a_i=n-1\),那么 \(k\) 一定是 \(n-1\) 的约数。但是如果直接找约数时间复杂度是 \(\mathcal O(\sqrt{n})\) 的,再加上遍历的复杂度 \(\mathcal O(n)\),总复杂度 \(\mathcal O(n\sqrt{n})\),不足以通过此题。

    思考一下,\(k\) 一定是 \(n-1\) 的某个质因子的倍数,因此如果我们令 \(k\) 为某个质因子,求出此情况下的 \(gcd(a_1,a_2,a_3,\cdots)\),则是真正的 \(k\),也只有这个 \(k\) 是可能有答案的。

    \(k=1\) 的答案就是 \(2^{n-1}-sum\)\(sum\) 表示 \(k>1\) 时的答案总数。因为每条边只有两种情况,总情况是 \(2^{n-1}\),有 \(sum\) 种情况的 \(gcd\) 不为 1,那么剩下的就是 \(gcd=1\) 的情况。

    Code

    #include<cstdio>
    #include<cstring>
    #define N 1000005
    #define mod 998244353
    using namespace std;
    struct node
    {
    	int to,next;
    }a[N<<1];
    int pt,T,n,tot,k,x,y,p[N],opt[N],ans[N],head[N],mi[N],c[N];
    bool flag,b[N];
    int read()
    {
    	int res=0,fh=1;char ch=getchar();
    	while (ch<'0'||ch>'9') {if (ch=='-') fh=-1;ch=getchar();}
    	while (ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch-'0'),ch=getchar();
    	return res*fh;
    }
    void add(int x,int y)
    {
    	a[++tot].to=y;
    	a[tot].next=head[x];
    	head[x]=tot;
    }
    void dfs(int x,int fa)
    {
    	if (!flag) return;
    	c[x]=0;
    	for (int i=head[x];i;i=a[i].next)
    	{
    		int v=a[i].to;
    		if (v==fa) continue;
    		dfs(v,x);
    		c[x]+=opt[v];
    	}
    	if (c[x]%k==0) opt[x]=1;
    	else
    	{
    		if ((c[x]+1)%k!=0) flag=false;
    		opt[x]=0;c[x]++;
    	}
    }
    int gcd(int x,int y)
    {
    	if (!y||!x) return x+y;
    	int r=x%y;
    	while (r) x=y,y=r,r=x%y;
    	return y;
    }
    int main()
    {
    	freopen("you.in","r",stdin);
    	freopen("you.out","w",stdout);
    	b[1]=true;mi[1]=2;
    	for (int i=2;i<=1000000;++i)
    	{
    		mi[i]=mi[i-1]*2%mod;
    		if (!b[i]) p[++pt]=i;
    		for (int j=1;j<=pt;++j)
    		{
    			int k=i*p[j];
    			if (k>1000000) break;
    			b[k]=true;
    			if (i%p[j]==0) break;
    		}
    	}
    	T=read();
    	while (T--)
    	{
    		tot=0;
    		n=read();
    		for (int i=1;i<=n;++i)
    			head[i]=ans[i]=0;
    		for(int i=1;i<n;++i)
    		{
    			x=read();y=read();
    			add(x,y);add(y,x);			
    		}
    		ans[1]=mi[n-1];
    		for (int i=1;i<=pt;++i)
    		{
    			if (p[i]>n-1) break;
    			if ((n-1)%p[i]==0)
    			{
    				k=p[i];
    				flag=true;
    				dfs(1,0);
    				if (flag)
    				{
    					int g=0;
    					for (int j=1;j<=n;++j)
    						g=gcd(g,c[j]);
    					if (g<n&&!ans[g]) ans[g]=1,ans[1]--;
    				}
    			}
    		}
    		for (int i=1;i<=n;++i)
    			printf("%d ",ans[i]);
    		printf("\n");
    	}
    	return 0;
    } 
    
  • 相关阅读:
    【模板】Sparse-Table
    UVa 11235 Frequent values
    【模板】树状数组
    UVa 1428 Ping pong
    数学技巧
    UVa 11300 Spreading the Wealth
    UVa 11729 Commando War
    UVa 11292 Dragon of Loowater
    POJ 3627 Bookshelf
    POJ 1056 IMMEDIATE DECODABILITY
  • 原文地址:https://www.cnblogs.com/Livingston/p/15558311.html
Copyright © 2011-2022 走看看