外星人
Time Limit: 3 Sec Memory Limit: 128 MB[Submit][Status][Discuss]
Description
Input
Output
输出test行,每行一个整数,表示答案。
Sample Input
1
2
2 2
3 1
2
2 2
3 1
Sample Output
3
HINT
Test<=50 Pi<=10^5,1<=Q1<=10^9
Main idea
给定一个数,用Πp[i]^q[i](p<=10^5,q<=10^9)的形式表示,问最少需要对这个数字x进行几次x=Φ(x)操作使得x=1。
Solution
这显然是一道数论题。
首先想到了只有Φ(2)=1,所以最后答案必然需要转成带2的形式,我们先考虑一个数字,由欧拉函数的推导公式Φ(Πp[i]^q[i])=Π(p[i]-1)*p[i]^(q[i]-1)可以发现每次求Φ会消去一个质因数2,并且产生若干个2(产生的2是有上限的)。
这句话是什么意思呢?
我们举个例子:讨论一个偶数180=2^2 * 3^2 * 5,Φ(180)=2^1 * (3-1)*3 * (5-1)=48,这里产生了3个2,消去了1个2。
所以我们只要求出产生了几个2即可(由于除了Φ(2)以外的数都是偶数,所以任意奇数只要经过一遍求Φ就可以变为偶数来处理,次数+1),因为每次只能消去一个1,所以答案就应该是这个数分解出的2的个数。
知道欧拉函数是一个积性函数,并且我们现在求的显然是一个完全积性函数,由于这个性质,求分解出几个2可以使用线性筛来实现,对于每一项p[i]^q[i]分解出的个数就是(p[i]分解出的个数*q[i]),答案就是Σ(每一项分解出的个数)。
Code
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<cmath> 7 #include<queue> 8 using namespace std; 9 10 const int ONE=100001; 11 12 int T; 13 int f[ONE],p[ONE],tot,phi[ONE]; 14 int x,y,m,PD; 15 long long Ans; 16 17 int get() 18 { 19 int res,Q=1; char c; 20 while( (c=getchar())<48 || c>57) 21 if(c=='-')Q=-1; 22 if(Q) res=c-48; 23 while((c=getchar())>=48 && c<=57) 24 res=res*10+c-48; 25 return res*Q; 26 } 27 28 void Get_f(int n) 29 { 30 phi[1]=1; 31 for(int i=2;i<=n;i++) 32 { 33 if(!f[i]) 34 { 35 p[++tot]=i; 36 phi[i]=phi[i-1]; 37 } 38 39 for(int j=1;j<=tot;j++) 40 { 41 if(i*p[j]>n) break; 42 f[i*p[j]]=1; 43 phi[i*p[j]]=phi[i]+phi[p[j]]; 44 if(i%p[j]==0) break; 45 } 46 } 47 } 48 49 int main() 50 { 51 Get_f(ONE-1); 52 T=get(); 53 while(T--) 54 { 55 m=get(); 56 Ans=PD=0; 57 for(int i=1;i<=m;i++) 58 { 59 x=get(); y=get(); 60 Ans+=(long long)phi[x]*y; 61 if(!PD && x==2) PD=1; 62 } 63 printf("%lld\n",Ans+(!PD)); 64 } 65 }