HDU5780 gcd 尤拉函式
gcd
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 732 Accepted Submission(s): 254
Problem Description
Little White learned the greatest common divisor, so she plan to solve a problem: given x, n, query ∑gcd(-1,−1) (1≤a,b≤n)
Input
The first line of input is an integer T ( 1≤T≤300) For each test case ,the single line contains two integers x and n ( 1≤x,n≤1000000)
Output
For each testcase, output a line, the answer mod 1000000007
Sample Input
5
3 1
4 2
8 7
10 5
10 8
Sample Output
2
24
2398375
111465
111134466
Source
題意:
a的取值範圍是[1,n],b的取值範圍是[1,n],求 之和
分析:
首先, ,問題轉化為求1到n,最大公約數為d的個數 * (x^d)-1的和
ans=∑s[d]∗(x^d−1),記s[d]=最大公約數為d的個數,也就是1到n/d以內,互質的對數,顯然是尤拉函式的字首和
s[d]=2*(phi[1]+phi[2]+...+phi[n/d])-1
注意到:d不同,但是n/d一樣,也就是s[d]可能有多個相同,比如 10/6 10/7 10/8 10/9 10/10,所以求s[d]相同的項,我們可以用等比公式求和(快速冪+逆元 ),直接進行除法會發生精度誤差,所以考慮求逆元
所以我們只要找到每一段s[d]就可以 即 r=n/(n/d),r為最後一個相同s[d]的下標,d為第一個s[d]相同的下標
由於第一個下標為d,最後一個下標為r,n=(r-d+1)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e6+7; #define mod 1000000007 ll phi[maxn]; void get_phi() { for(int i=1;i<maxn;i++) phi[i]=i; for(int i=2;i<maxn;i++) if(phi[i]==i) for(int j=i;j<maxn;j+=i) phi[j]=phi[j]/i*(i-1); for(int i=3;i<maxn;i++) phi[i]=(phi[i]+phi[i-1])%mod; for(int i=2;i<maxn;i++) phi[i]=(2*phi[i]+1)%mod; } ll quickPow(ll a,ll b) { ll res=1; while(b){ if(b&1) res=(res*a)%mod; a=a*a%mod; b>>=1; } return res; } int main() { get_phi(); int T; scanf("%d",&T); while(T--){ ll x,n; scanf("%lld%lld",&x,&n); if(x==1) { printf("0\n"); continue; } ll ans=0; ll inv=quickPow(x-1,mod-2);//費馬小定理求逆元 for(int i=1;i<=n;i=n/(n/i)+1) { ll r=n/(n/i);//閉區間終點,i為閉區間起點 ll part=((quickPow(x,i)*(quickPow(x,r-i+1)-1)%mod)*inv%mod-(r-i+1)+mod)%mod;//等比數列求和 ans=(ans+(phi[n/i]*part)%mod+mod)%mod; } printf("%lld\n",(ans+mod)%mod); } return 0; }