【JZOJ 省選模擬】最大公約數

題目

Description
在這裏插入圖片描述
在這裏插入圖片描述

Input
從文件 divisor.in 中讀入數據。
只有一行,輸入一個整數n 。

Output
輸出到文件 divisor.out 中。
輸出一行,一個整數,表示式子的結果。由於三葉只需要你的驗證而不是給出答案,所以你只需要輸出答案(式子的值)對 10^+7取模的值。

Sample Input
Sample Input1
3

Sample Input2
985

Sample Output
Sample Output1
15

Sample Output2
349880989

Data Constraint
在這裏插入圖片描述

思路

首先對式子進行反演
在這裏插入圖片描述
發現後面那一部分可以整除劃分,前面那一部分可以杜教篩。
注意,要預處理多一些否則會T

代碼

#include<cstdio>
#define P(x,y) x=(x+y)%mod
#define ll long long
using namespace std;
const int A=1e7,mod=1e9+7,M=1e6+3;
ll n,x,ans,mu[A+9],v[34567890],rf[M],rg[M];
int tot=2*A,ps,p[A+9],f[M],g[M];
bool b[M*10];
ll G(ll n)
{
	if(!n) return 0;
	if(n<=A) return v[A+n];
	int x=n%M; while(rg[x]&&rg[x]!=n)x=(x+1)%M;
	if(rg[x]==n) return v[g[x]];
	int _=g[x]=++tot; rg[x]=n;
	for(ll i=2,j; i<=n; i=j+1)
	{
		j=n/(n/i);
		P(v[_],(i+j)%mod*(j-i+1)%mod*(mod+1>>1)%mod*G(n/i));
	}
	return v[_]=(1-v[_]+mod)%mod;
}
ll F(ll n)
{
	if(!n) return 0;
	if(n<=A) return v[n];
	int x=n%M; while(rf[x]&&rf[x]!=n)x=(x+1)%M;
	if(rf[x]==n) return v[f[x]];
	int _=f[x]=++tot; rf[x]=n;
	for(ll i=1,j; i<=n; i=j+1)
	{
		j=n/(n/i);
		P(v[_],(j-i+1)%mod*G(n/i));
	}
	return v[_];
}
int main()
{
	freopen("divisor.in","r",stdin); freopen("divisor.out","w",stdout);
	mu[1]=1,v[1]=1,v[A+1]=1;
	for(int i=2; i<=A; i++)
	{
		if(!b[i]) mu[p[++ps]=i]=mod-1,v[i]=mod-i+1;
		v[A+i]=(v[A+i-1]+i*mu[i])%mod;
		for(int j=1;j<=ps&&(j==1||i%x)&&i*(x=p[j])<=A;j++)
		{
			b[i*x]=1,mu[i*x]=i%x?(mod-mu[i])%mod:0;
			v[i*x]=i%x?v[i]*v[x]%mod:v[i];
		}
	}
	for(int i=2; i<=A; i++) P(v[i],v[i-1]);
	scanf("%lld",&n);
	for(ll i=1,j,k; i<=n; i=j+1)
	{
		j=n/(k=n/i); k%=mod;
		P(ans,k*(k+1)/2%mod*k%mod*(F(j)-F(i-1)+mod));
	}
	printf("%lld",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章