1. 程式人生 > >cogs2745[濟南集訓 2017] 求gcd之和【解題報告】

cogs2745[濟南集訓 2017] 求gcd之和【解題報告】

text tar problem ace == clas ++ aps 解題報告

題目鏈接

題目大意:

給定n、m,求出(1--n)所有數與(1--m)所有數的gcd之和。

看完題解後可以發現一個有用的結論:

對於一個數,他的所有因子的歐拉值之和等於這個數本身。

例如8這個數字,他的因子分別有1,2,4,8,對應歐拉值為1,1,2,4。

那麽我們可以對題目的詢問做一下改變。

對於gcd(i,j)的值,我們可以求出他所有因子的歐拉值,加起來即為gcd(i,j)的值。

換一個思路,我們枚舉每一個因子,看他作為哪一對(i,j)的一個因子出現,每有一對貢獻就+1。

而枚舉到x時,對數很容易發現是(m/x)*(n/x)。

那麽這個因子的總貢獻即為phi[x]*(m/x)*(n/x)。

附上代碼:

技術分享圖片
 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int inf=1e7+10;
 5 const int mod=998244353; 
 6 int n,m;
 7 bool p[inf];
 8 vector<int>pls;
 9 ll phi[inf];
10 void get_phi(int x){
11     phi[1]=1;
12     for(int i=2;i<=x;i++){
13 if(!p[i]){ 14 pls.push_back(i); 15 phi[i]=i-1; 16 } 17 int siz=pls.size(); 18 for(int j=0;j<siz&&pls[j]*i<=n;j++){ 19 p[i*pls[j]]=1; 20 if(i%pls[j]==0){ 21 phi[i*pls[j]]=phi[i]*pls[j]%mod;
22 break; 23 } 24 else phi[i*pls[j]]=phi[i]*(pls[j]-1)%mod; 25 } 26 } 27 } 28 int main() 29 { 30 freopen("hoip.in","r",stdin); 31 freopen("hoip.out","w",stdout); 32 scanf("%d%d",&n,&m); 33 if(n>m)swap(n,m); 34 get_phi(n); 35 ll ans=0; 36 for(int i=1;i<=n;i++){ 37 ans+=phi[i]*(m/i)%mod*(n/i)%mod; 38 ans%=mod; 39 } 40 printf("%lld\n",ans); 41 return 0; 42 }
代碼君

cogs2745[濟南集訓 2017] 求gcd之和【解題報告】