huntian oy (数论&卷积&杜教筛)

huntian oy (数论&卷积&杜教筛)

思路:

f ( n , a , b ) = ∑ i = 1 n ∑ j = 1 i g c d ( i a − j a , i b − j b ) [ g c d ( i , j ) = 1 ] ( m o d 1 0 9 + 7 ) f(n,a,b)=\sum\limits_{i=1}^n \sum\limits_{j=1}^i gcd(i^a-j^a,i^b-j^b)[gcd(i,j)=1]\pmod{10^9+7} f(n,a,b)=i=1nj=1igcd(iaja,ibjb)[gcd(i,j)=1](mod109+7)

g c d ( i a − j a , i b − j b ) gcd(i^a-j^a,i^b-j^b) gcd(iaja,ibjb)

i a − j a = ( i − j ) ( i a − 1 + i a − 2 j + ⋯ + j a − 1 ) i^a-j^a=(i-j)(i^{a-1}+i^{a-2}j+\dots+j^{a-1}) iaja=(ij)(ia1+ia2j++ja1)

i b − j b = ( i − j ) ( i b − 1 + i b − 2 j + ⋯ + j b − 1 ) i^b-j^b=(i-j)(i^{b-1}+i^{b-2}j+\dots+j^{b-1}) ibjb=(ij)(ib1+ib2j++jb1)

因为 a , b a,b a,b互质。

所以 g c d ( i a − j a , i b − j b ) = i − j gcd(i^a-j^a,i^b-j^b)=i-j gcd(iaja,ibjb)=ij

原式 = ∑ i = 1 n ∑ j = 1 i ( i − j ) [ g c d ( i , j ) = 1 ] = ∑ i = 1 n i × φ ( i ) − ∑ i = 1 n ∑ j = 1 i j [ g c d ( i , j ) = 1 ] = ∑ i = 1 n i × φ ( i ) − ( ∑ i = 1 n i × φ ( i ) 2 − 1 2 ) = ∑ i = 1 n i × φ ( i ) − 1 2 =\sum\limits_{i=1}^n \sum\limits_{j=1}^i (i-j)[gcd(i,j)=1]\\=\sum\limits_{i=1}^n i\times \varphi(i)-\sum\limits_{i=1}^n \sum\limits_{j=1}^i j[gcd(i,j)=1]\\=\sum\limits_{i=1}^n i\times \varphi(i)-(\sum\limits_{i=1}^n \dfrac{i\times \varphi(i)}{2}-\dfrac{1}{2})\\=\dfrac{\sum\limits_{i=1}^n i\times \varphi(i)-1}{2} =i=1nj=1i(ij)[gcd(i,j)=1]=i=1ni×φ(i)i=1nj=1ij[gcd(i,j)=1]=i=1ni×φ(i)(i=1n2i×φ(i)21)=2i=1ni×φ(i)1

然后一股神秘的卷积力量可将式子变为递推式。(这里卷积学的不好待补)

S ( n ) = ∑ i = 1 n i 2 − ∑ i = 2 n i S ( n i ) S(n)=\sum\limits_{i=1}^n i^2-\sum\limits_{i=2}^n iS(\dfrac{n}{i}) S(n)=i=1ni2i=2niS(in)

对于 n ≤ 1 0 6 n\le 10^6 n106的数据可用第一个式子。

否则用递推式记忆化递归。

φ ( i ) \varphi(i) φ(i) 用欧拉筛即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e6+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define il inline
ll inv2,inv6,phi[N];
ll ksm(ll a,ll n){
	ll ans=1;
	while(n){
		if(n&1) ans=ans*a%mod;
		a=a*a%mod;
		n>>=1;
	}
	return ans;
}
int a[N],p[N],cnt;
void Euler(int n){
	 phi[1]=1;
	 for(int i=2;i<=n;i++){
	 	  if(!a[i]){
	 	  	  p[++cnt]=i;
	 	  	  phi[i]=i-1;
		   }
		   for(int j=1;j<=cnt&&p[j]*i<=n;j++){
		   		a[p[j]*i]=1;
		   		if(i%p[j]==0){
		   			  phi[p[j]*i]=phi[i]*p[j];
		   			  break;
				   }
				else phi[p[j]*i]=phi[i]*phi[p[j]];
		   }
	 }
	 for(int i=2;i<=n;i++){
	 	phi[i]=(phi[i-1]+phi[i]*i%mod)%mod;
	 }
}
unordered_map<int,int>mp;
int solve(int n){
	if(n<=N-5) return phi[n];
	if(mp[n]) return mp[n];
	ll tmp=1LL*n*(n+1)%mod*(2*n+1)%mod*inv6%mod;	//这里要用3个mod 
	for(int l=2,r;l<=n;l=r+1){
		r=n/(n/l);
		tmp-=1LL*(r-l+1)*(l+r)/2%mod*solve(n/l)%mod;
		tmp=(tmp%mod+mod)%mod;		 
	} 
	return mp[n]=tmp;
}
int main(){
	inv2=ksm(2,mod-2),inv6=ksm(6,mod-2);
	int t;
	Euler(N-5);
	scanf("%d",&t);
	while(t--){
		int n,a,b;
		scanf("%d%d%d",&n,&a,&b);
		int ans=1LL*(solve(n)-1)*inv2%mod; 
		ans=(ans%mod+mod)%mod;
		printf("%d\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酷酷的Herio

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值