洛谷P3768 简单的数学题 杜教筛+莫比乌斯反演


洛谷P3768 简单的数学题


标签

  • 莫比乌斯反演
  • 狄利克雷卷积
  • 杜教筛

前言

  • 我的csdn和博客园是同步的,欢迎来访danzh-博客园~
  • 很简单很好推~

简明题意


  • ∑ i = 1 n ∑ j = 1 n i j g c d ( i , j ) ( 模 p 意 义 下 ) \sum_{i=1}^n\sum_{j=1}^nijgcd(i,j)(模p意义下) i=1nj=1nijgcd(i,j)(p)

思路

  • 很简单鸭。顺着推一遍就出来了~
    ∑ i = 1 n ∑ j = 1 n i j g c d ( i , j ) \sum_{i=1}^n\sum_{j=1}^nijgcd(i,j) i=1nj=1nijgcd(i,j)
  • 改为枚举gcd:
    ∑ x = 1 n x ∑ i = 1 n ∑ j = 1 n i j [ g c d ( i , j ) = = x ] \sum_{x=1}^nx\sum_{i=1}^n\sum_{j=1}^nij[gcd(i,j)==x] x=1nxi=1nj=1nij[gcd(i,j)==x]

都是套路啊!倍加式中出现 g c d ( i , j ) gcd(i,j) gcd(i,j),则改为枚举

  • 见到 [ g c d ( i , j ) = = x ] [gcd(i,j)==x] [gcd(i,j)==x]再熟悉不过了,但我还是一步步的说吧。先更换枚举上限:
    ∑ x = 1 n x 3 ∑ i = 1 [ n x ] ∑ j = 1 [ n x ] i j [ g c d ( i , j ) = = 1 ] \sum_{x=1}^nx^3\sum_{i=1}^{[\frac nx]}\sum_{j=1}^{[\frac nx]}ij[gcd(i,j)==1] x=1nx3i=1[xn]j=1[xn]ij[gcd(i,j)==1]

这里简单说一下为什么是 x 3 x^3 x3。因为更换枚举上限后,枚举的是就是原来的 1 x \frac 1x x1,所以ij都变成了原来的 1 x \frac 1x x1,所以应该乘上 x 2 x^2 x2,然后再移到前面就是 x 3 x^3 x3

  • 然后反演鸭,用 ∑ d ∣ n μ ( d ) \sum_{d|n}\mu(d) dnμ(d)替换 [ g c d ( i , j ) = = 1 ] [gcd(i,j)==1] [gcd(i,j)==1],并且将 d ∣ g c d ( i , j ) d|gcd(i,j) dgcd(i,j)改为 d ∣ i 且 d ∣ j d|i且d|j didj得到:
    ∑ x = 1 n x 3 ∑ i = 1 [ n x ] ∑ j = 1 [ n x ] i j ∑ d ∣ i 且 d ∣ j μ ( d ) \sum_{x=1}^nx^3\sum_{i=1}^{[\frac nx]}\sum_{j=1}^{[\frac nx]}ij\sum_{d|i且d|j}\mu(d) x=1nx3i=1[xn]j=1[xn]ijdidjμ(d)

记得关于gcd的性质: d ∣ g c d ( i , j )    ⟺    d ∣ i 且 d ∣ j d|gcd(i,j)\iff d|i且d|j dgcd(i,j)didj

  • 然后就又是套路了,替换后就改为枚举d,那么就是:
    ∑ x = 1 n x 3 ∑ d = 1 [ n x ] μ ( d ) ∑ i = 1 [ n x ] ∑ j = 1 [ n x ] i j [ d ∣ i 且 d ∣ j ] \sum_{x=1}^nx^3\sum_{d=1}^{[\frac nx]}\mu(d)\sum_{i=1}^{[\frac nx]}\sum_{j=1}^{[\frac nx]}ij[d|i且d|j] x=1nx3d=1[xn]μ(d)i=1[xn]j=1[xn]ij[didj]
  • 然后看到 [ d ∣ i 且 d ∣ j ] [d|i且d|j] [didj]我们就又忍不住跟换枚举上限了,记得换了上限后,枚举的数成了原来的 1 d \frac 1d d1,所以应该乘回去:
    ∑ x = 1 n x 3 ∑ d = 1 [ n x ] μ ( d ) ∑ i = 1 [ n d x ] ∑ j = 1 [ n d x ] i j d 2 \sum_{x=1}^nx^3\sum_{d=1}^{[\frac nx]}\mu(d)\sum_{i=1}^{[\frac n{dx}]}\sum_{j=1}^{[\frac n{dx}]}ijd^2 x=1nx3d=1[xn]μ(d)i=1[dxn]j=1[dxn]ijd2
  • 小学奥数告诉我们 g ( x ) = ∑ i = 1 x ∑ j = 1 x i j = x 2 ∗ ( x + 1 ) 2 / 4 g(x)=\sum\limits_{i=1}^x\sum\limits_{j=1}^xij=x^2*(x+1)^2/4 g(x)=i=1xj=1xij=x2(x+1)2/4,所以原式实际是求:
    ∑ x = 1 n ∑ d = 1 [ n x ] μ ( d ) g ( [ n d x ] ) d 2 x 3 \sum_{x=1}^n\sum_{d=1}^{[\frac nx]}\mu(d)g([\frac n {dx}])d^2x^3 x=1nd=1[xn]μ(d)g([dxn])d2x3

上面的小学奥数式子是开玩笑的。实际上是这样推导的: g ( x ) = ∑ i = 1 x ∑ j = 1 x i j = ∑ i = 1 x i ∑ i = 1 x i = ( n ∗ ( n + 1 ) / 2 ) 2 g(x)=\sum\limits_{i=1}^x\sum\limits_{j=1}^xij=\sum\limits_{i=1}^xi\sum\limits_{i=1}^xi=(n*(n+1)/2)^2 g(x)=i=1xj=1xij=i=1xii=1xi=(n(n+1)/2)2

  • 这个时候一看,x和d的上限的关系,就发现可以更换枚举项,我们改为枚举 K = d x K=dx K=dx,然后原式就是:
    ∑ k = 1 n k 2 g ( [ n k ] ) ∑ d ∣ k μ ( k d ) d \sum_{k=1}^nk^2g([\frac nk])\sum_{d|k}\mu(\frac kd)d k=1nk2g([kn])dkμ(dk)d

这一步如何改为枚举 K = d x K=dx K=dx的,不清楚的同学请看我的博客《数论公式总结》戳这里

  • 很显然 ∑ d ∣ k μ ( k d ) d \sum\limits_{d|k}\mu(\frac kd)d dkμ(dk)d就是 μ 和 i d \mu和id μid的狄利克雷卷积鸭!人尽皆知 μ ∗ i d = ϕ \mu*id=\phi μid=ϕ,所以我们实际求:
    ∑ k = 1 n k 2 ϕ ( k ) g ( [ n k ] ) \sum_{k=1}^nk^2\phi(k)g([\frac nk]) k=1nk2ϕ(k)g([kn])

  • 这里一看g里面的 n k \frac nk kn,就知道要分块了~所以哦我们需要求出 k 2 μ ( k ) k^2\mu(k) k2μ(k)的前缀和,暴力显然是不行的,因此我们杜教筛呗,所以现在问题就是如何杜教筛

  • 现在要求的是 x 2 ϕ ( x ) x^2\phi(x) x2ϕ(x)的前缀和,我们令 f ( x ) = x 2 ϕ ( x ) f(x)=x^2\phi(x) f(x)=x2ϕ(x),再找一个函数 g ( x ) g(x) g(x),于是杜教筛一下:
    S ( n ) g ( 1 ) = ∑ i = 1 n f ∗ g − ∑ i = 2 n g ( i ) S ( [ n i ] ) S(n)g(1)=\sum_{i=1}^nf*g-\sum_{i=2}^ng(i)S([\frac ni]) S(n)g(1)=i=1nfgi=2ng(i)S([in])

  • 其实,当杜教筛找 g ( x ) g(x) g(x)时,往往更注重的是 f ∗ g f*g fg的狄利克雷卷积的前缀和好求,通常两者卷积是 ϵ \epsilon ϵ或者 i d id id或者 ϕ ( n ) \phi(n) ϕ(n)。因此现在需要找到一个 g ( x ) g(x) g(x),使得 f ∗ g f*g fg ϵ \epsilon ϵ或者 i d id id。我们写出两者的卷积:
    ( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) g ( [ n d ] ) (f*g)(n)=\sum_{d|n}f(d)g([\frac nd]) (fg)(n)=dnf(d)g([dn])

  • 我们把 f ( x ) = x 2 ϕ ( x ) f(x)=x^2\phi(x) f(x)=x2ϕ(x)带进去,得出 f f f g g g的卷积是:
    ( f ∗ g ) ( n ) = ∑ d ∣ n d 2 ϕ ( d ) g ( [ n d ] ) (f*g)(n)=\sum_{d|n}d^2\phi(d)g([\frac nd]) (fg)(n)=dnd2ϕ(d)g([dn])

  • 到了这里,是不是很容易确定 g g g呢?如果令 g = i d 2 g=id^2 g=id2,会发现 d 2 d^2 d2被消掉了耶。那么 f f f g g g的卷积是:
    ( f ∗ g ) ( n ) = ∑ d ∣ n d 2 ϕ ( d ) n d n d = ∑ d ∣ n ϕ ( d ) n 2 = n 2 ∑ d ∣ n ϕ ( d ) = n 3 (f*g)(n)=\sum_{d|n}d^2\phi(d)\frac nd\frac nd=\sum_{d|n}\phi(d)n^2=n^2\sum_{d|n}\phi(d)=n^3 (fg)(n)=dnd2ϕ(d)dndn=dnϕ(d)n2=n2dnϕ(d)=n3

∑ d ∣ n ϕ ( d ) = n \sum\limits_{d|n}\phi(d)=n dnϕ(d)=n,n得约数得欧拉函数之和是n,这是常用的结论!!!

  • 把上面的卷积带入杜教筛中,可以得:
    S ( n ) = ∑ i = 1 n i 3 − ∑ i = 2 n g ( i ) S ( [ n i ] ) S(n)=\sum_{i=1}^ni^3-\sum_{i=2}^ng(i)S([\frac ni]) S(n)=i=1ni3i=2ng(i)S([in])

  • 由小学奥数可以 O ( 1 ) O(1) O(1)求出 i 3 i^3 i3的前缀和,然后杜教筛写出来就A啦!!


注意事项

  • 在计算 i 3 , i 2 i^3,i^2 i3,i2前缀和是会溢出,要算一下乘法逆元。而且, i i i可能大于模数,应该先取模再运算

总结

  • 其实,当杜教筛找 g ( x ) g(x) g(x)时,往往更注重的是 f ∗ g f*g fg的狄利克雷卷积的前缀和好求,通常两者卷积是 ϵ \epsilon ϵ或者 i d id id。因此现在需要找到一个 g ( x ) g(x) g(x),使得 f ∗ g f*g fg ϵ \epsilon ϵ或者 i d id id。常见的狄利克雷卷积见我的另一篇博客戳这里
  • 总结几个求和公式:
    ∑ i = 1 n i 3 = ∑ i = 1 n ∑ j = 1 n i j = ( n ( n − 1 ) 2 ) 2 \sum_{i=1}^ni^3=\sum_{i=1}^n\sum_{j=1}^nij=\left( \frac {n(n-1)}2 \right)^2 i=1ni3=i=1nj=1nij=(2n(n1))2
    ∑ i = 1 n i 2 = n ( n + 1 ) ( 2 n + 1 ) 6 \sum_{i=1}^ni^2=\frac {n(n+1)(2n+1)}6 i=1ni2=6n(n+1)(2n+1)

AC代码

#include<cstdio>
#include<unordered_map>
using namespace std;

const int maxn = 1e7 + 10;

long long n;
int mod;
unordered_map<long long, int> rec;

int ksm(int a, int b)
{
	int ans = 1, base = a % mod;
	while (b)
	{
		if (b & 1)
			ans = 1ll * ans * base % mod;
		base = 1ll * base * base % mod;
		b >>= 1;
	}
	return ans;
}

bool no_prime[maxn];
int prime[maxn], phi[maxn], pre_phi[maxn];
int shai(int n)
{
	int cnt = 0;
	phi[1] = 1;

	for (int i = 2; i <= n; i++)
	{
		if (!no_prime[i])
			prime[++cnt] = i, phi[i] = i - 1;

		for (int j = 1; j <= cnt && prime[j] * i <= n; j++)
		{
			no_prime[prime[j] * i] = 1;
			phi[prime[j] * i] = i % prime[j] == 0 ? phi[i] * prime[j] : phi[i] * (prime[j] - 1);
			if (i % prime[j] == 0) break;
		}
	}

	for (int i = 1; i <= n; i++)
		pre_phi[i] = (pre_phi[i - 1] + 1ll * phi[i] * i % mod * i) % mod;

	return cnt;
}

int inv2;
int inv6;

int pre_x2(long long n)
{
	n %= mod;
	return n * (n + 1) % mod * (2 * n + 1) % mod * inv6 % mod;
}

int pre_x3(long long n)
{
	n %= mod;
	return (n * (n + 1) % mod * inv2 % mod) * (n * (n + 1) % mod * inv2 % mod) % mod;
}

int S(long long n)
{
	if (n <= maxn - 10) return pre_phi[n];
	if (rec[n]) return rec[n];
	int ans = pre_x3(n);
	
	long long l = 2, r;
	while (l <= n)
	{
		r = n / (n / l);
		ans = (ans - (pre_x2(r) - pre_x2(l - 1)) * 1ll * S(n / l)) % mod;
		l = r + 1;
	}
	return rec[n] = ans;
}

void solve()
{
	scanf("%d%lld", &mod, &n);
	shai(maxn - 10);
	inv2 = ksm(2, mod - 2);
	inv6 = ksm(6, mod - 2);

	long long l = 1, r;
	int ans = 0;
	while (l <= n)
	{
		r = n / (n / l);
		int gg = (S(r) - S(l - 1));
		ans = (ans + 1ll * (S(r) - S(l - 1)) * 1ll * pre_x3(n / l)) % mod;
		l = r + 1;
		//printf("%d\n", gg);
	}
	
	printf("%d", (ans % mod + mod) % mod);
}

int main()
{
	solve();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值