2749: [HAOI2012]外星人
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 377 Solved: 199
[Submit][Status]
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
Source
题解:
终于把这题搞掉了。。。
研究了一下此题的两种解法。
一种是直接求 这个数一直phi,最后能phi出多少个2,就是答案。
一种是利用递推的思想,用 f[i]表示i phi几次能变成1,有递推式 f[i]=f[phi(i)]+1
这两种方法都可以求出正确结果,让我们讨论一下为什么这样就可以:
首先,
题中给出了这样的公式,然后我们发现每次phi只能使每个质数的指数-1,然后这个 p[i]-1会继续质因数分解然后加在其它比它小的质数的指数上。
然后我们就会发现,2被phi的次数一定是最多的!!!
假设还有另一个质数 x 那么 phi(x)会多出1个2,所以 phi(2)的次数>=phi(x) 的次数!
所以 2被phi了多少次,ans就是多少!2还没有被phi完,其他质数的质数就已经都为0了!
然后呢?我们得到了一个什么结论?一个数被phi成1的次数就等于它phi了多少次2
这样的话 f[x]就等于 x phi 2的次数。
然后两种方法就统一了。
这也就解释了为什么不同的质数之间的被phi的次数是可以叠加的,因为我们加的实际上是同一个质数2的次数,而phi每次只能让2的指数-1!!!
还有一些细节要注意,这里就不提出了。
代码:直接递推求 f[x](求phi写萎了。。。)(这里面的偶数求的会比实际少1,因为并没有计入第一次phi的2)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int m=200010; 7 int p[m],f[m],n,t,i,j,x,y; 8 long long ans; 9 int main() 10 { 11 for(i=1;i<=m;i++) p[i]=i; 12 for(i=2;i<=m;i++) 13 if(p[i]==i) 14 for(j=i;j<=m;j+=i) p[j]=p[j]/i*(i-1); 15 p[1]=1,f[1]=-1; 16 for(i=2;i<=m;i++) f[i]=f[p[i]]+1; 17 f[1]++,f[2]++; 18 cin>>t; 19 while(t--) 20 { 21 scanf("%d",&n); 22 for(ans=1,i=1;i<=n;i++) 23 { 24 scanf("%d%d",&x,&y); 25 if(x==2) ans--; 26 ans+=(long long)f[x]*y; 27 } 28 printf("%lld\n",ans); 29 } 30 return 0; 31 } 32