Loading

HDU-6960 Necklace of Beads 置换-Burnside引理

HDU-6960 Necklace of Beads 置换-Burnside引理

题意

给长度为\(n\)的项链涂上红色、蓝、绿三种颜色 并且要求绿色不超过\(k\)个 任意相邻的也不同色

求本质不同的方案数

分析

那么若用\(g(n,k)\)表示对长度\(n\)的环染色且绿色个数为\(k\)的方案数(不要求本质不同)

那么当旋转\(i\)次后,就可以得到\((n,i)\)个循环节,循环节长度为\(\frac{n}{(n,i)}\) ,且要求每个循环节颜色相同。

同时要么整段都是绿色 要么都不是绿色 那么枚举绿色的个数有

\[\sum|X^g| =\sum_{j = 0}^{\frac{k(i,n)}{n}}g((n,i),j) \]

套用Burnside引理

\[|X/G| = \frac{1}{n}\sum_{g \in G}|X^g| \]

\[ans= \frac{1}{n}\sum_{i=0}^{n -1}\sum_{j=0}^{\frac{k(i,n)}{n}}g((n,i),j) \]

考虑\(g(n,k)\)的求法 就是要求任意两个绿色的间隔大于0,间隔之间只有红绿红.. 或者绿红绿... 所以需要乘上\(2^k\)

而绿色方法就是经典的隔板法 -> 考虑\(x_1 + x_2 + ..x_k = n - m\)的解即可\(x_i > 0\) 当然还要注意讨论环带来的影响

那么再进行简单的数论变换

即可得到

\[ans = \frac{1}{n} \sum_{d|n}\phi(\lfloor\frac{n}{d}\rfloor)\sum_{j=0}^{\lfloor\frac{kd}{n}\rfloor}g(d,j) \]

代码

#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
typedef long long ll;


ll rd(){
	ll x;
	scanf("%lld",&x);
	return x;
}

const int MOD = 998244353;
const int maxn = 1e6 + 5;

int phi[maxn];
int fac[maxn];
int iv[maxn];

inline void add(int &x,int y){
	x += y;
	if(x >= MOD) x -= MOD;
}


inline int ksm(int a,int b = MOD - 2,int m = MOD){
	int ans = 1;
	int base = a;
	while(b){
		if(b & 1) ans = (ll)ans * base % MOD;
		base = (ll)base * base % MOD;
		b >>= 1;
	}
	return ans;
}

inline int C(int n,int m){
	if(m > n) return 0;
	return (ll)((ll)fac[n] * iv[n - m] % MOD) * iv[m] % MOD;
}

inline int get(int n,int k){
	if(!k) {
		if(n & 1) return 0;
		return 2;
	}
	return (C(n - k,k) + C(n - k - 1,k - 1)) % MOD;
}

int _2[maxn];

inline int add(int k,int d,int n){
	int ans = 0;
	int lim = (ll)k * d / n;
	for(int i = 0;i <= lim;i++){
		add(ans,(ll)_2[i] * get(d,i) % MOD);
	}
	return ans;
}


int main(){
	phi[1] = 1;
	for(int i = 2;i < maxn;i++){
		if(!phi[i]) {
			for(int j = i;j < maxn;j += i){
				if(!phi[j]) phi[j] = j;
				phi[j] = (ll)phi[j] / i * (i - 1);
			}
		}
	}
	fac[0] = 1;
	iv[0] = ksm(1);
	_2[0] = 1;
	for(int i = 1;i < maxn;i++)
		fac[i] = (ll)fac[i - 1] * i % MOD,_2[i] = (ll)_2[i - 1] * 2 % MOD,iv[i] = ksm(fac[i]);
	int T = rd();
	while(T--){
		int ans = 0;
		int n = rd();
		int k = rd();
		for(int i = 1;i * i <= n;i++){
			if(n % i) continue;
			add(ans,(ll)phi[n / i] * add(k,i,n) % MOD);
			if(i * i == n) break;
			add(ans,(ll)phi[i] * add(k,n / i,n) % MOD);
		}
		ans = (ll)ans * ksm(n) % MOD;
		printf("%d\n",ans);
	}
}
posted @ 2021-07-30 15:32  MQFLLY  阅读(53)  评论(0编辑  收藏  举报