【SDOI2013】项链 题解

3 篇文章 0 订阅

【SDOI2013】项链

Problem

众所周知。

Solution

将原问题分为两个问题求解。

Part 1

首先求珍珠的种类数。
f i f_i fi表示满足 g c d = i gcd = i gcd=i的本质不同珍珠个数,
g i g_i gi表示满足 g c d gcd gcd i i i的倍数的本质不同珍珠个数
f 1 f_1 f1就是答案
由定义可得 g ( i ) = ∑ i ∣ d f ( d ) g(i)=\sum_{i|d}f(d) g(i)=idf(d)
m o b i u s mobius mobius反演得到 f ( i ) = ∑ i ∣ d μ ( d i ) g ( d ) f(i)=\sum_{i|d}\mu(\frac{d}{i})g(d) f(i)=idμ(id)g(d)
所以 f ( 1 ) = ∑ i = 1 a μ ( i ) g ( i ) f(1)=\sum_{i =1}^{a}\mu(i)g(i) f(1)=i=1aμ(i)g(i)
下面计算 g ( i ) g(i) g(i)
i i i的倍数有 ⌊ a i ⌋ \lfloor\frac{a}{i}\rfloor ia
考虑旋转和翻折产生的六个置换
B u r n s i d e Burnside Burnside引理有 g ( i ) = ⌊ a i ⌋ 3 + 3 ⌊ a i ⌋ 2 + 2 ⌊ a i ⌋ 6 g(i)=\frac{\lfloor\frac{a}{i}\rfloor^3+3\lfloor\frac{a}{i}\rfloor^2+2\lfloor\frac{a}{i}\rfloor}{6} g(i)=6ia3+3ia2+2ia
数论分块即可

Part 2

知道了珍珠的种类数后求本质不同的项链数
先设珍珠的种类数为 c c c
不考虑本质不同的条件,先设 h ( i ) h(i) h(i)为相邻不同,首尾不同项链数
初值 h ( 1 ) = 0 , h ( 2 ) = c ( c − 1 ) h(1)=0,h(2)=c(c-1) h(1)=0,h(2)=c(c1)
考虑转移 讨论放入一个珍珠,左右两边是否相同
若左右相同,则贡献为 ( c − 1 ) h ( i − 2 ) (c-1)h(i-2) (c1)h(i2)
若左右不同,则贡献为 ( c − 2 ) h ( i − 1 ) (c-2)h(i-1) (c2)h(i1)
综上 h ( i ) = ( c − 2 ) h ( i − 1 ) + ( c − 1 ) h ( i − 2 ) h(i)=(c-2)h(i-1)+(c-1)h(i-2) h(i)=(c2)h(i1)+(c1)h(i2)
注意到这是一个二阶常系数递推关系,特征方程法求得通解为 h ( i ) = ( c − 1 ) i + ( − 1 ) i ( c − 1 ) h(i)=(c-1)^i+(-1)^i(c-1) h(i)=(c1)i+(1)i(c1)
考虑本质不同的方案数
设旋转i位, x j x_j xj为第j位的种类
x j = x ( j + i ) m o d n x_j = x_{(j+i) mod n} xj=x(j+i)modn
将其看作第 j j j个点向第 ( j + i ) m o d n (j+i)modn (j+i)modn个点连一条边
则整个项链成为许多个环,环内个点选的种类相同
环的长度为 i n l c m ( i , ) = n g c d ( i , n ) \frac{in}{lcm(i,)}=\frac{n}{gcd(i,n)} lcm(i,)in=gcd(i,n)n
每个环互不相交,因此只需考虑 n n g c d ( i , n ) = g c d ( i , n ) \frac{n}{\frac{n}{gcd(i,n)}}=gcd(i,n) gcd(i,n)nn=gcd(i,n)个珍珠的 h ( ) h() h()
由Burnside引理
a n s = 1 n ∑ i = 1 n h ( g c d ( i , n ) ) ans=\frac{1}{n}\sum_{i=1}^{n}h(gcd(i,n)) ans=n1i=1nh(gcd(i,n))
枚举 g c d ( i , n ) gcd(i,n) gcd(i,n),上式成为
a n s = 1 n ∑ d ∣ n ∑ i = 1 n [ g c d ( i , n ) = = d ] h ( d ) = 1 n ∑ d ∣ n ∑ i = 1 n [ g c d ( n d , i d ) = = 1 ] h ( d ) = 1 n ∑ d ∣ n φ ( n d ) h ( d ) \begin{aligned} ans &=\frac{1}{n}\sum_{d|n}\sum_{i=1}^{n}[gcd(i,n)==d]h(d)\\ &=\frac{1}{n}\sum_{d|n}\sum_{i=1}^{n}[gcd(\frac{n}{d},\frac{i}{d})==1]h(d)\\ &=\frac{1}{n}\sum_{d|n}\varphi(\frac{n}{d})h(d) \end{aligned} ans=n1dni=1n[gcd(i,n)==d]h(d)=n1dni=1n[gcd(dn,di)==1]h(d)=n1dnφ(dn)h(d)
大概的思路到这里就结束了.但是有些细节需要注意.比如 φ ( n d ) \varphi(\frac{n}{d}) φ(dn)无法直接求,需要分解质因数.模数可能会整除 n n n
丑码贴在下面

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const LL mod = 1e9 + 7;
const LL MOD = mod * mod;
LL c, n, cnt, ans, a, y[10000][2];
int vis[10000010], prime[10000000], cnt2, T, mu[10000010], sum[10000010];
LL read() {
	LL res, flag = 1; char ch = getchar();
	for(; ch > '9' || ch < '0'; ch = getchar())
		if(ch == '-') flag = -1;
	for(res = 0; ch >= '0' && ch <= '9'; res = res * 10 + LL(ch - '0'), ch = getchar());
	return res * flag;
}
LL mul(LL x, LL y, LL mo) {
	LL z = (long double) x * y / mo + 0.5; 
	z = x * y - z * mo;
	return (z % mo + mo) % mo;
}
LL Qpower(LL x, LL pnt, LL mo){
	LL res = 1;
	x = x % mo;
	while(pnt) {
		if(pnt & 1) res = mul(res, x, mo);
		x = mul(x, x, mo);
		pnt >>= 1;
	}
	return res;
}
LL F(LL x) {return (Qpower(c - 1, x, MOD) + (MOD + (x & 1 ? -1 : 1) * (c - 1)) % MOD) % MOD;}
void dfs(int k, LL p, LL x) {
	if(k > cnt2) {
		ans = (ans + mul(p, F(n / x), MOD)) % MOD;
		return ;
	}
	dfs(k + 1, p, x);
	for(int i = 1; i < y[k][1]; ++i) {
		p /= y[k][0];
		x /= y[k][0];
		dfs(k + 1, p, x);
	}
	dfs(k + 1, p / (y[k][0] - 1), x / y[k][0]);
}
int main() {
	T = read();
	mu[1] = 1, sum[1] = 1;
	for(int i = 2; i <= 1e7; ++i) {
		if(!vis[i]) prime[++cnt] = i, mu[i] = -1;
		for(int j = 1; j <= cnt && i * prime[j] <= 1e7; ++j) {
			vis[i * prime[j]] = 1;
			if(i % prime[j] == 0) break;
			mu[i * prime[j]] = - mu[i];
		}
		sum[i] = sum[i - 1] + mu[i];
	}
	while(T--) {
		ans = c = cnt2 = 0;
		memset(y, 0, sizeof(y));
		n = read(), a = read();
		for(LL l = 1, r; l <= a; l = r + 1) {
			LL m = a / l;
			r = a / m;
			c = (c + mul((sum[r] - sum[l - 1] + MOD) % MOD, mul(((mul(m, mul(m, m, MOD), MOD) + 3 * mul(m, m, MOD) % MOD) % MOD + m * 2 % MOD) % MOD, 833333345000000041ll, MOD), MOD)) % MOD;
		}
		LL tmp = n, p = n;
		for(int i = 1; i <= cnt && prime[i] <= tmp; ++i) {
			if(tmp % prime[i] == 0) {
				y[++cnt2][0] = prime[i];
				p = p / prime[i] * (prime[i] - 1);
				while(tmp % prime[i] == 0) {
					y[cnt2][1] ++;
					tmp /= prime[i];
				}
			}
		}
		if(tmp > 1) {
			p = p / tmp * (tmp - 1);
			y[++cnt2][0] = tmp;
			y[cnt2][1] = 1;
		}
		dfs(1, p, n);
		if(n % mod == 0) ans = ans / mod * Qpower(n / mod, mod - 2, mod) % mod;
		else ans = ans % mod * Qpower(n, mod - 2, mod) % mod;
		printf("%lld\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值