2019 西安邀请赛 B. Product(莫比乌斯反演 + 杜教筛 + 欧拉降幂)

本文探讨了在数学算法竞赛中,如何运用莫比乌斯反演解决复杂的三重乘法求和问题。通过对原始表达式的巧妙转换,将问题转化为更易处理的形式,最终通过编程实现高效求解。

在这里插入图片描述
如图:求 ∏i=1n∏j=1n∏k=1nmgcd(i,j)[k∣gcd(i,j)]\prod_{i = 1}^n\prod_{j = 1}^n\prod_{k = 1}^nm^{gcd(i,j)[k | gcd(i,j)]}i=1nj=1nk=1nmgcd(i,j)[kgcd(i,j)]


把求和符号放到幂次就变成求和符号,幂次式子变成:∑i=1n∑j=1n∑k=1ngcd(i,j)[k∣gcd(i,j)]\sum_{i = 1}^n\sum_{j = 1}^n\sum_{k = 1}^ngcd(i,j)[k|gcd(i,j)]i=1nj=1nk=1ngcd(i,j)[kgcd(i,j)]开始莫比乌斯反演:∑i=1n∑j=1n∑k=1ngcd(i,j)[k∣gcd(i,j)]\sum_{i = 1}^n\sum_{j = 1}^n\sum_{k = 1}^ngcd(i,j)[k|gcd(i,j)]i=1nj=1nk=1ngcd(i,j)[kgcd(i,j)]=∑k=1nk∑i=1⌊nk⌋∑j=1⌊nk⌋gcd(i,j)=\sum_{k = 1}^nk\sum_{i = 1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j = 1}^{\lfloor\frac{n}{k}\rfloor}gcd(i,j)=k=1nki=1knj=1kngcd(i,j)=∑k=1nk∑i=1⌊nk⌋∑j=1⌊nk⌋∑p∣gcd(i,j)ϕ(p)=\sum_{k = 1}^nk\sum_{i = 1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j = 1}^{\lfloor\frac{n}{k}\rfloor}\sum_{p | gcd(i,j)}\phi(p)=k=1nki=1knj=1knpgcd(i,j)ϕ(p)=∑k=1nk∑p=1⌊nk⌋ϕ(p)∑i=1⌊nk∗p⌋∑j=1⌊nk∗p⌋=∑k=1nk∑p=1⌊nk⌋ϕ(p)∗⌊nk∗p⌋2=\sum_{k = 1}^nk\sum_{p = 1}^{\lfloor\frac{n}{k}\rfloor}\phi(p)\sum_{i = 1}^{\lfloor\frac{n}{k*p}\rfloor}\sum_{j = 1}^{\lfloor\frac{n}{k*p}\rfloor}=\sum_{k = 1}^nk\sum_{p = 1}^{\lfloor\frac{n}{k}\rfloor}\phi(p)*{\lfloor\frac{n}{k*p}\rfloor}^2=k=1nkp=1knϕ(p)i=1kpnj=1kpn=k=1nkp=1knϕ(p)kpn2=∑T=1n∑k∣Tk∗ϕ(Tk)∗⌊nT⌋2=\sum_{T = 1}^n\sum_{k | T}k*\phi(\frac{T}{k})*{\lfloor\frac{n}{T}\rfloor}^2=T=1nkTkϕ(kT)Tn2
S(T)=∑k∣Tk∗ϕ(Tk)S(T) = \sum_{k | T}k*\phi(\frac{T}{k})S(T)=kTkϕ(kT),需要用杜教筛预处理S函数的前缀和。
S=ϕ∗IdS = \phi*IdS=ϕIdS∗I=ϕ∗Id∗I=μ∗Id∗I∗Id=Id∗Id=n∗d(n)S * I = \phi * Id * I = \mu * Id * I * Id = Id * Id = n * d(n)SI=ϕIdI=μIdIId=IdId=nd(n)
n∗d(n)n * d(n)nd(n) 不能 O(1) 计算前缀和。
转化式子:∑i=1ni∗d(i)=∑i=1ni∑j∣i1=∑j=1nj∑i=1⌊nj⌋i\sum_{i = 1}^n i * d(i) = \sum_{i = 1}^ni\sum_{j | i}1 = \sum_{j = 1}^nj\sum_{i = 1}^{\lfloor\frac{n}{j}\rfloor}ii=1nid(i)=i=1niji1=j=1nji=1jni
转化成这样可以暴力在n\sqrt nn时间内求和,加上记忆化,会使得杜教筛复杂度达到大概 O(n34)O(n^{\frac{3}{4}})O(n43)左右

分块求出幂次和之后求快速幂即可,幂次取模用欧拉定理,模数 mod = ϕ(p)\phi(p)ϕ(p)


代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 10;
bool ispri[maxn];
int pri[maxn],cnt[maxn],tot;
ll sum[maxn],tp[maxn];
ll n,m,mod,inv2,inv6,sqr;
ll ans[maxn];
map<ll,ll> mp,np;
ll fpow(ll a,ll b) {
	ll r = 1;
	while(b) {
		if(b & 1) r = r * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return r;
}
void sieve(int n) {
	ispri[0] = ispri[1] = true;
	pri[0] = 0;sum[0] = 0;cnt[0] = 0;
	sum[1] = 1;
	for(int i = 2; i <= n; i++) {
		if(!ispri[i]) {
			pri[++pri[0]] = i;
			tp[i] = i;
			cnt[i] = 1;
			sum[i] = 2 * i - 1;
		}
		for(int j = 1; j <= pri[0] && i * pri[j] <= n; j++) {
			ispri[i * pri[j]] = true;
			if(i % pri[j] == 0) {
				tp[i * pri[j]] = tp[i] * pri[j];
				cnt[i * pri[j]] = cnt[i] + 1;
				ll c = cnt[i * pri[j]];
				ll tmp = ((c + 1) * tp[i * pri[j]] % mod - c * tp[i] % mod + mod) % mod;
				sum[i * pri[j]] = sum[i / tp[i]] * tmp % mod;
				break;
			}
			tp[i * pri[j]] = pri[j];
			cnt[i * pri[j]] = 1;
			sum[i * pri[j]] = sum[i] * sum[pri[j]] % mod;
		}
	}
	for(int i = 1; i <= n; i++)
		sum[i] = (sum[i] + sum[i - 1]) % mod;
}
ll cal(ll x) {
	return x * (x + 1) / 2 % mod;
}
ll cal2(ll x) {
	return x * (x + 1) % mod * (2 * x + 1) % mod * inv6 % mod;
}
ll getans(ll x) {
	ll tmp = 0;
	for(ll i = 1,j; i <= x; i = j + 1) {
		j = x / (x / i);
		tmp += (cal(j) - cal(i - 1) + mod) % mod * cal(x / i) % mod;
		tmp %= mod;
	}
	return tmp;
}
ll getsum(ll x) {
	if(x <= 2000000) return sum[x];
	if(mp[x]) return mp[x];
	ll res = getans(x);
	for(ll i = 2,j; i <= x; i = j + 1) {
		j = x / (x / i);
		res = (res + mod - (j - i + 1) * getsum(x / i) % mod) % mod;
	}
	return mp[x] = res;
}
int main() {
	scanf("%lld%lld%lld",&n,&m,&mod);
	mod--;
	sieve(2000000);
	inv2 = fpow(2,mod - 2);inv6 = fpow(6,mod - 2);
	ll tot = 0;
	for(ll i = 1,j; i <= n; i = j + 1) {
		j = n / (n / i);
		tot += (getsum(j) + mod - getsum(i - 1)) % mod * (n / i) % mod * (n / i) % mod;
		tot %= mod; 
	}
	mod++;
	printf("%lld\n",fpow(m,tot));
	return 0;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值