洛谷 P3307 - [SDOI2013]项链(Burnside 引理+数论)

题面传送门

看到题目我们显然可以将题目拆分成两部分:首先求出有多少个符合要求的珠子 \(c\),这样我们就可以将每种珠子看成一种颜色,题目也就等价于有多少种用 \(c\) 种颜色染长度为 \(n\) 的环的方法,满足相邻格子颜色不同,可以通过旋转重合的染色方案算同一种,这就是题目的第二部分。显然两部分是独立的,因此可以分开来计算。

首先考虑怎样求出 \(c\) 的值,注意到这里涉及 \(\gcd\),故可以套路地想到莫比乌斯反演,记 \(f(i)\) 为珠子上三个数 \(\gcd\) 恰好为 \(i\) 的方案数,\(g(i)\) 为珠子上三个数 \(\gcd\)\(i\) 的倍数的方案数,那么显然有 \(g(i)=\sum\limits_{i\mid j}f(j)\),莫反一下显然有 \(f(i)=\sum\limits_{i\mid j}\mu(\dfrac{j}{i})g(j)\),最终答案 \(c=f(1)=\sum\limits_{i=1}^a\mu(i)g(i)\),故只需求出 \(g(i)\) 即可求出 \(f(1)\),接下来考虑怎样求出 \(g(i)\),由于珠子上三个数都是 \(i\) 的倍数,那么该值就等价于珠子上三个数都不超过 \(m=\lfloor\dfrac{a}{i}\rfloor\) 的方案数,而由于此题要求本质不同的珠子个数,故考虑 Burnside 定理,假设珠子上三个数为 \((a,b,c)\),那么 \((a,b,c)\)\((a,c,b),(b,a,c),(b,c,a),(c,a,b),(c,b,a)\) 是本质上相同的,即 \((a,b,c)\times p\),其中 \(p\) 是可以是任意一个三阶置换,我们对于每个 \(p\) 都构造一个以小置换 \((a,b,c)\) 为元素的大置换 \(P_p\),其中 \((a,b,c)\)\(P_p\) 中对应的元素为 \((a,b,c)\times p\),那么显然这 \(3!=6\) 个大置换构成了一个置换群,我们要求的即为这个置换群中等价类的个数,而由 Burnside 定理其就等于 \(\dfrac{1}{6}\sum\limits_{p}c(P_p)\),再由 Polya 定理 \(P_p\) 中不动点的个数就是 \(m^{p\text{中置换环的个数}}\),故 \(g(i)=\dfrac{1}{6}(2m+3m^2+m^3)\),整除分块一下即可在 \(\sqrt{a}\) 的时间内求出 \(c\)(虽然不用整除分块问题也不大)

接下来考虑题目的第二部分,我们将全部 \(c\) 种珠子编号 \(1,2,\cdots,c\),那么题目等价于求有多少种用 \(c\) 种颜色染长度为 \(n\) 的环的方法,满足相邻格子颜色不同,可以通过旋转重合的染色方案算同一种。看到本质不同,继续考虑 Burnside 定理,根据模板题的套路它就等于 \(\dfrac{1}{n}\sum\limits_{d\mid n}\varphi(\dfrac{n}{d})q(d)\),其中 \(q(d)\) 为用 \(c\) 种颜色染长度为 \(d\) 的纸片,满足相邻格子颜色不同,首尾格子颜色也不同的方案数。首先考虑怎样求出 \(\varphi(\dfrac{n}{d})\),暴力 \(\sqrt{n}\) 求复杂度会达到 \(d(n)\sqrt{n}\),无法通过,不过我们发现我们计算的 \(\varphi(i)\) 都是 \(n\) 的因数,故考虑将 \(n\) 分解质因数,然后一遍 DFS 预处理出所有 \(n\) 的因数的 \(\varphi\),用 std::map 存储,这样复杂度可降到 \(\sqrt{n}+d(n)\log n\)。最后考虑怎样求 \(p(d)\),一个很 naive 的想法是 \(p(d)=c(c-2)(c-1)^{d-2}\),不过这显然是错误的,因为对于第一个格子的颜色与第 \(d-1\) 个格子颜色相同与不同的情况,第 \(d\) 个格子染色的方案数也是不同的,因此考虑分两种情况讨论,若第一个格子的颜色与第 \(d-1\) 个格子颜色相同,那么可视作对于长度为 \(d-2\) 的纸片,将最后一个格子劈成两份,并拿一份放到开头,再在中间插入一个格子,即 \(p(d)\leftarrow p(d-2)\times(c-1)\),若第一个格子的颜色与第 \(d-1\) 个格子颜色不同,那么可视作对于长度为 \(d-1\) 的纸片,在最后一个格子后面插入一个格子,即 \(p(d)\leftarrow p(d-1)\times(c-2)\)。故 \(p(d)=p(d-2)\times(c-1)+p(d-1)\times(c-2)\),特征根方程推推,\(x^2-(c-2)x-(c-1)=0\),解得 \(x_1=-1,x_2=c-1\),待定系数法设 \(p(d)=\alpha(-1)^{d}+\beta(c-1)^d\),那么显然 \(p(1)=0,p(2)=c(c-1)\),故 \(\begin{cases}\beta(c-1)-\alpha=0\\\beta(c-1)^2+\alpha=c(c-1)\end{cases}\),解得 \(\begin{cases}\alpha=c-1\\\beta=1\end{cases}\),故 \(p(d)=(c-1)(-1)^d+(c-1)^d\),大功告成。

最后还有一点,就是由于 \(n\le 10^{14}\),可能出现 \((10^9+7)\mid n\) 的情况,这种情况下 \(n\) 不存在 \(\mod 10^9+7\) 意义下的逆元,因此需将模数变为 \((10^9+7)^2\),这样在最后乘以 \(\dfrac{1}{n}\) 之前的答案 \(ans\) 一定是 \(10^9+7\) 的倍数,这样我们只需将 \(ans\) 除以 \(10^9+7\),然后再乘上 \(\dfrac{n}{10^9+7}\) 的逆元即可,这时候需要写龟速乘,否则会爆 ll。

const int MAXV=1e7;
int mu[MAXV+5],pr[MAXV/10+5],prcnt=0,sum[MAXV+5];
bitset<MAXV+5> vis;
void sieve(int n){
	mu[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){pr[++prcnt]=i;mu[i]=-1;}
		for(int j=1;j<=prcnt&&pr[j]*i<=n;j++){
			vis[pr[j]*i]=1;
			if(i%pr[j]==0) break;
			mu[i*pr[j]]=-mu[i];
		}
	}
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+mu[i];
}
ll smul(ll x,ll y,ll mod){
	if(x<0) x=(x%mod+mod)%mod;
	if(y<0) y=(y%mod+mod)%mod;
	ll ret=0;
	for(;y;y>>=1,x=(x+x)%mod) if(y&1) ret=(ret+x)%mod;
	return ret;
}
ll qpow(ll x,ll e,ll mod){
	ll ret=1;
	for(;e;e>>=1,x=smul(x,x,mod)) if(e&1) ret=smul(ret,x,mod);
	return ret;
}
const ll MOD1=1e9+7;
const ll MOD2=MOD1*MOD1;
ll INV6_1=qpow(6,MOD1-2,MOD1);
ll INV6_2=qpow(6,MOD1*(MOD1-1)-1,MOD2);
ll MOD,INV6;map<ll,ll> phi;
void dfs(int x,vector<pair<ll,int> > fac,ll mul,ll phim){
	if(x==fac.size()) return phi[mul]=phim,void();
	for(int i=0;i<=fac[x].se;i++){
		if(i){
			mul=mul*fac[x].fi;
			if(i==1) phim=phim*(fac[x].fi-1);
			else phim=phim*fac[x].fi;
		} dfs(x+1,fac,mul,phim);
	}
}
ll calc(ll k,ll n){return smul(k-1,((n&1)?-1:1)+qpow(k-1,n-1,MOD),MOD);}
void solve(){
	ll n,k=0;int a;scanf("%lld%d",&n,&a);
	if(n%MOD1==0) MOD=MOD2,INV6=INV6_2;
	else MOD=MOD1,INV6=INV6_1;
	for(int l=1,r;l<=a;l=r+1){
		r=(a/(a/l));ll lim=a/l,cnt=0;
		cnt=(cnt+smul(lim,smul(lim,lim,MOD),MOD))%MOD;
		cnt=(cnt+smul(3*lim,lim,MOD))%MOD;cnt=(cnt+2*lim)%MOD;
		cnt=smul(cnt,sum[r]-sum[l-1],MOD);cnt=smul(cnt,INV6,MOD);
		k=(k+cnt)%MOD;//printf("%d %d %lld\n",l,r,cnt);
	} //printf("%lld\n",k);
	vector<ll> fac;ll tmp=n;
	vector<pair<ll,int> > fac_dec;
	for(ll i=1;i*i<=n;i++) if(n%i==0){
		fac.pb(i);if(n/i!=i) fac.pb(n/i);
	}
	for(ll i=2;i*i<=n;i++) if(tmp%i==0){
		int cnt=0;
		while(tmp%i==0) tmp/=i,cnt++;
		fac_dec.pb(mp(i,cnt));
	} if(tmp>1) fac_dec.pb(mp(tmp,1));
	phi.clear();dfs(0,fac_dec,1,1);ll ans=0;
	for(ll x:fac) ans=(ans+smul(phi[n/x],calc(k,x),MOD))%MOD;
//	printf("%lld\n",ans);
	if(n%MOD1) ans=smul(ans,qpow(n,MOD1-2,MOD1),MOD1);
	else ans=smul(ans/MOD1,qpow(n/MOD1,MOD1*(MOD1-1)-1,MOD2),MOD2);
	printf("%lld\n",ans%MOD1);
}
int main(){
	int qu;scanf("%d",&qu);sieve(MAXV);
	while(qu--) solve();
	return 0;
}
posted @ 2021-04-24 14:54  tzc_wk  阅读(114)  评论(0)    收藏  举报