caioj 1290: 之乎者也

i = 1 n ( j = 1 i g c d ( i , j ) ) m o d    1 0 9 + 7 ( n 5 1 0 7 ) \prod_{i=1}^n (\sum_{j=1}^igcd(i,j))\mod 10^9+7(n\le 5*10^7)

本来想出一道莫比乌斯反演的题目的,但是 \sum 太简单了,就换成了 \prod 试试看,结果发现一些奇怪的东西…

定义 f ( n ) = i = 1 n g c d ( i , n ) f(n)=\sum_{i=1}^n gcd(i,n) ,则有:

{ f ( p k ) = 1 ( p k p k 1 ) + p ( p k 1 p k 2 ) . . . + p k = k ( p k p k 1 ) + p k ( g c d ) f ( n ) = f ( p ) f ( q ) ( p q ) \begin{cases} f(p^k)=1(p^k-p^{k-1})+p(p^{k-1}-p^{k-2})...+p^k=k(p^k-p^{k-1})+p^k(枚举gcd大小并求出次数)\\f(n)=f(p)f(q)(p\bot q)\end{cases}

第二个式子是证明它是积性函数的:

n = p c q d ( p q ) n=p^c q^d(p\bot q) ,则需要证明 i = 1 n g c d ( i , n ) = j = 1 p c g c d ( p c , j ) k = 1 q d g c d ( q d , k ) \sum_{i=1}^n gcd(i,n)=\sum_{j=1}^{p^c} gcd(p^c,j)\sum_{k=1}^{q^d} gcd(q^d,k) .

此时我们计算一下 p a q b ( a c , b d ) p^aq^b(a\le c,b\le d) 作为gcd的出现次数.

从左边看则为 n p a q b n p a + 1 q b n p a q b + 1 + n p a + 1 q b + 1 \dfrac{n}{p^aq^b}-\lfloor\dfrac{n}{p^{a+1}q^b}\rfloor-\lfloor\dfrac{n}{p^aq^{b+1}}\rfloor+\lfloor\dfrac{n}{p^{a+1}q^{b+1}}\rfloor .

从右边看则为 ( p c a p c a 1 ) ( q d b q d b 1 ) (p^{c-a}-\lfloor p^{c-a-1}\rfloor)(q^{d-b-\lfloor q^{d-b-1}\rfloor}) .

很明显,拆开后是等价的.

那么我们只要求出 f ( p k ) f(p^k) 及其出现次数,用一下快速幂即可.

本算法的瓶颈在于线性筛,因为快速幂是高度压缩了运算次数.

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7,N=5e7+10;
ll ans;
ll power_mod(ll a,ll b) {
	ll c=1;a%=mod;
	while(b) {
		if(b&1)c=c*a%mod;
		a=a*a%mod;b=b>>1;
	}
	return c;
}
void calc(int x,ll y,ll p) {
	int cnt=0;
	do {
		x/=p;cnt++;
		ans=ans*power_mod(y*p+cnt*y*(p-1),x-x/p)%mod;
		y*=p;
	}while(x>=p);
}
int n,prime[3001144],tot;bool v[N];
void get_prime() {
	for(int i=2;i<=n;i++) {
		if(!v[i])prime[++tot]=i,calc(n,1,i);
		for(int j=1;i*prime[j]<=n;j++) {
			v[i*prime[j]]=1;
			if(i%prime[j]==0)break;
		}
	}
}
int main() {
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	scanf("%d",&n);ans=1;
	get_prime();printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/107399797