CF1554E You

题面


题解

注意a[u]是点u位置的a,不是每选一个点然后把非标记个数丢进vector里(

每选择一个点,相当于把相邻的非标记的边标为外向,最后一个点u的外向边个数就是a[u]

又观察发现每种边定向方案都可以构造(拓扑),所以一共有2^(n-1)种方案

设f[k]表示gcd=k,g[k]表示k|gcd,求出g之后反演一下


显然g[1]=2^(n-1);对于g[k>1],发现叶子必定内向,然后去掉叶子后的下一层唯一确定父亲边方向,如此类推得到方案唯一,因此可以O(n)判断一个g[k]是否存在

找到任意一个叶子的父亲,记为sp,则a[sp]必为son[sp]或son[sp]+1,即k|son[sp]或k|(son[sp]+1),因此check之前先判一下,这样要O(n)check的k就只有根号(其实是σ(n))个了

总复杂度\(O(n\sqrt n)\)


不用反演的话,gcd=k就先用k|gcd来求(唯一),最后求gcd判一下,多一个log

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (int a=b; a<=c; a++)
#define fd(a,b,c) for (int a=b; a>=c; a--)
#define add(a,b) a=((a)+(b))%mod
#define mod 998244353
#define ll long long
#define file
using namespace std;

const int N=1e5+10;
int a[N*2][2],ls[N],len;
int p[N],miu[N],lenp;
bool bz[N];
vector<int> v;
int son[N],sum[N],fa[N],sp;
ll f[N],g[N];
int T,n;

void init()
{
	int l=100000;
	miu[1]=1;
	fo(i,2,l)
	{
		if (!bz[i])
		p[++lenp]=i,miu[i]=-1;
		
		fo(j,1,lenp)
		if (1ll*i*p[j]<=l)
		{
			bz[i*p[j]]=1;
			miu[i*p[j]]=-miu[i];
			if (i%p[j]==0)
			{
				miu[i*p[j]]=0;
				break;
			}
		}
		else
		break;
	}
}
void New(int x,int y)
{
	++len;
	a[len][0]=y;
	a[len][1]=ls[x];
	ls[x]=len;
}

ll qpower(ll a,int b)
{
	ll ans=1;
	while (b)
	{
		if (b&1) ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}

void dfs(int Fa,int t)
{
	int i;
	fa[t]=Fa;
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	{
		++son[t];
		dfs(t,a[i][0]);
	}
	
	v.push_back(t);
	if (sp==0 && son[t]) sp=t;
}

int check(int k)
{
	if (!(son[sp]%k==0 || (son[sp]+1)%k==0)) return 0;
	memset(sum,0,(n+1)*4);
	fo(i,0,n-2)
	{
		if (sum[v[i]]%k==0) ++sum[fa[v[i]]];
		else
		if ((sum[v[i]]+1)%k!=0) return 0;
	}
	if (sum[1]%k==0) return 1;
	else return 0;
}

void solve()
{
	scanf("%d",&n);
	len=0;sp=0;
	memset(ls,0,(n+1)*4);
	memset(f,0,(n+1)*8);
	memset(g,0,(n+1)*8);
	memset(son,0,(n+1)*4);
	memset(sum,0,(n+1)*4);
	fo(i,1,n-1)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		New(x,y),New(y,x);
	}
	
	if (n==2)
	{
		f[1]=2;
		f[2]=0;
	}
	else
	{
		v.clear();
		dfs(0,1);
		
		g[1]=qpower(2,n-1);
		fo(k,2,n) g[k]=check(k);
		
		fo(i,1,n)
		{
			for (int j=i; j<=n; j+=i)
			add(f[i],g[j]*miu[j/i]);
		}
	}
	fo(i,1,n) printf("%lld ",f[i]);
	printf("\n");
}

int main()
{
//	freopen("CF1554E.in","r",stdin);
	
	init();
	scanf("%d",&T);
	for (;T;--T) solve();
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2024-11-04 00:17  gmh77  阅读(6)  评论(0编辑  收藏  举报