CF1554E You

gmh77發表於2024-11-04

題面


題解

注意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;
}

相關文章