
如图:求 ∏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=1n∏j=1n∏k=1nmgcd(i,j)[k∣gcd(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=1∑nj=1∑nk=1∑ngcd(i,j)[k∣gcd(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=1∑nj=1∑nk=1∑ngcd(i,j)[k∣gcd(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=1∑nki=1∑⌊kn⌋j=1∑⌊kn⌋gcd(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=1∑nki=1∑⌊kn⌋j=1∑⌊kn⌋p∣gcd(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=1∑nkp=1∑⌊kn⌋ϕ(p)i=1∑⌊k∗pn⌋j=1∑⌊k∗pn⌋=k=1∑nkp=1∑⌊kn⌋ϕ(p)∗⌊k∗pn⌋2=∑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=1∑nk∣T∑k∗ϕ(kT)∗⌊Tn⌋2
令S(T)=∑k∣Tk∗ϕ(Tk)S(T) = \sum_{k | T}k*\phi(\frac{T}{k})S(T)=∑k∣Tk∗ϕ(kT),需要用杜教筛预处理S函数的前缀和。
S=ϕ∗IdS = \phi*IdS=ϕ∗Id,S∗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)S∗I=ϕ∗Id∗I=μ∗Id∗I∗Id=Id∗Id=n∗d(n)
n∗d(n)n * d(n)n∗d(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}i∑i=1ni∗d(i)=∑i=1ni∑j∣i1=∑j=1nj∑i=1⌊jn⌋i
转化成这样可以暴力在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;
}

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

被折叠的 条评论
为什么被折叠?



