2749: [HAOI2012]外星人

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 377  Solved: 199
[Submit][Status]

Description

 

Input

 

Output

输出test行,每行一个整数,表示答案。

Sample Input

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

这两种方法都可以求出正确结果,让我们讨论一下为什么这样就可以:

首先,BZOJ2749: [HAOI2012]外星人

题中给出了这样的公式,然后我们发现每次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 
View Code

相关文章: