2021杭电多校1 1011/HDU 6960 Necklace of Beads

题目链接:https://acm.hdu.edu.cn/showproblem.php?pid=6960

题目大意:一串手链有n个珠子,有三种颜色红蓝绿,求相邻颜色不同且绿色染色数不超过k的本质不同的染色方案数,这里说的本质不同为两种染色方案不能通过旋转相同

题目思路:根据Burnside原理

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

\(f_{n,m}\)为给n个珠子染色,绿色不超过m的不考虑本质不同的染色方案数,根据Pólya原理,旋转i个会将置换分为gcd(i,n)段,每段长\(\frac{n}{gcd(i,n)}\),这种情况下的不动点可看做\(f_{gcd(i,n),j}\)

\[ans =\frac{1}{n}\sum_{i=1}^{n}\sum_{j=0}^{\lfloor \frac{k\cdot\mathrm{gcd}(i,n)}{n}\rfloor} f_{gcd(i,n),j}\\ =\frac{1}{n}\sum_{d|n}\sum_{i=1}^{n}[\mathrm{gcd}(i,n)=d]\sum_{j=0}^{\lfloor \frac{kd}{n}\rfloor} f_{d,j}\\ =\frac{1}{n}\sum_{d|n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}[\mathrm{gcd}(i,n)=1]\sum_{j=0}^{\lfloor \frac{kd}{n}\rfloor}f_{d,j}\\ =\frac{1}{n}\sum_{d|n}\varphi(\lfloor\frac{n}{d}\rfloor)F(d,\left \lfloor \frac{kd}{n} \right \rfloor) \]

现在问题转化成如何求\(f_{n,m}\),首先假设我们放好了m个绿色后会形成m个空,每个空都有2种情况:红蓝红蓝红……,蓝红蓝红蓝……,共\(2^{m}\)种情况,然后我们考虑怎么放绿色的,放绿色点的方案数等于在长度为n的手链上选取m个不相邻的点的方案数,也分两种情况,假设现在放了0个绿色的点,即在剩下的n-m个空中放m个绿色,方案数为\(C\binom{m}{n-m}\),假设现在放了1个绿色的点,其左右都不能放绿色,即在剩下的n-m-1个空中放m-1个绿色,方案数为\(C\binom{m-1}{n-m-1}\),故\(f_{n,m}=2^{m}\left (C\binom{m}{n-m}+C\binom{m-1}{n-m-1} \right )\)

AC代码:
话说C++超时了但G++AC了

#include <unordered_map>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <stack>
#include <deque>
#include <queue>
#include <cmath>
#include <map>
#include <set>
using namespace std;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10, M = 4e7 + 10;
const int base = 1e9;
const int P = 131;
const int mod = 998244353;
const double eps = 1e-8;
const double PI = acos(-1.0);
ll fac[N], inv[N], pow2[N];
int phi[N], pri[N];
bool st[N];
int pos;
ll ksm(ll a, ll b)
{
	ll res = 1 % mod;
	while (b)
	{
		if (b & 1)
			res = (res * a) % mod;
		a = (a * a) % mod;
		b >>= 1;
	}
	return res;
}
void inif(int n)
{
	phi[1] = 1;
	for (int i = 2; i <= n; ++i)
	{
		if (!st[i])
		{
			phi[i] = i - 1;
			pri[++pos] = i;
		}
		for (int j = 1; pri[j] <= n / i; ++j)
		{
			st[pri[j] * i] = true;
			if (i % pri[j] == 0)
			{
				phi[pri[j] * i] = phi[i] * pri[j];
				break;
			}
			phi[pri[j] * i] = phi[i] * (pri[j] - 1);
		}
	}
	fac[0] = inv[0] = 1;
	for (int i = 1; i < n; ++i)
	{
		fac[i] = (fac[i - 1] * i) % mod;
		inv[i] = ksm(fac[i], mod - 2);
	}
	pow2[0] = 1;
	for (int i = 1; i < n; ++i)
		pow2[i] = pow2[i - 1] * 2 % mod;
}
ll C(ll n, ll m)
{
	return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
ll F(ll n, ll k)
{
	ll res = n & 1 ? 0 : 2;
	for (ll m = 1; m <= min(k, n / 2); ++m)
		res = (res + pow2[m] * (C(n - m, m) + C(n - m - 1, m - 1)) % mod) % mod;
	return res;
}
int main()
{
	inif(N - 1);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		ll n, k;
		scanf("%lld%lld", &n, &k);
		ll ans = 0;
		for (ll i = 1; i * i <= n; ++i)
		{
			if (n % i == 0)
			{
				ll d = i;
				ans = (ans + phi[n / d] * F(d, k * d / n) % mod) % mod;
				if (i != n / i)
				{
					d = n / i;
					ans = (ans + phi[n / d] * F(d, k * d / n) % mod) % mod;
				}
			}
		}
		ans = ans * ksm(n, mod - 2) % mod;
		printf("%lld\n", ans);
	}
	return 0;
}

posted @ 2021-07-25 09:24  xiaopangpang7  阅读(44)  评论(0编辑  收藏  举报