【BZOJ 2749】 2749: [HAOI2012]外星人 (数论-线性筛?类积性函数)

2749: [HAOI2012]外星人

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的x表示phi的x阶函数,即phi[phi[phi[...phi[N]]]]],x个phi。。。

  然后不会做。。。

  我们先来熟悉一下欧拉函数

  

2-100欧拉函数表
n φ(n)
1 1
2 1
3 2
4 2
5 4
6 2
7 6
8 4
9 6
10 4
11 10
12 4
13 12
14 6
15 8
16 8
17 16
18 6
19 18
20 8
21 12
22 10
23 22
24 8
25 20
26 12
27 18
28 12
29 28
30 8
31 30
32 16
33 20
34 16
35 24
36 12
37 36
38 18
39 24
40 16
41 40
42 12
43 42
44 20
45 24
46 22
47 46
48 16
49 42
50 20
51 32
52 24
53 52
54 18
55 40
56 24
57 36
58 28
59 58
60 16
61 60
62 30
63 36
64 32
65 48
66 20
67 66
68 32
69 44
70 24
71 70
72 24
73 72
74 36
75 40
76 36
77 60
78 24
79 78
80 32
81 54
82 40
83 82
84 24
85 64
86 42
87 56
88 40
89 88
90 24
91 72
92 44
93 60
94 46
95 72
96 32
97 96
98 42
99 60
100 40

  2333333。。。。。。。

  然后就知道只有2的phi是1【你是不是智障啊。。。。

  再来熟悉一下phi的求法。。。就是每次分解质因数,然后把每个质因数 指数减一 然后增加一个p[i]-1

  然后我就还是不会做。。

  可以发现,你每次都会弄出至少一个2,因为除了2其他质数都是奇数,减一后都是偶数。

  你也会每次消掉一个2,(如果第一次没有2给你消,第二次极其之后都一定有二给你消,所以后面判断如果一开始是奇数就加一)

  直到只剩下一个2了,然后phi变成了1。

  不用想太多,就是问x这个数在phi的过程中能产生多少个2

  比如47->23->11->5->2->1 产生了5个2。

  就是这个意思吧。。。然后满足f[xy]=f[x]+f[y]这个很明显吧?【不是积性函数啊。。但是比积性函数更优越了因为你可以随便求

  【当然类似积性函数这样求还是很好的

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 100010
 8 #define LL long long
 9 
10 int pri[Maxn],pl;
11 LL f[Maxn];
12 bool vis[Maxn];
13 
14 void init()
15 {
16     pl=0;
17     memset(vis,0,sizeof(vis));
18     f[1]=1;
19     for(int i=2;i<=Maxn-10;i++)
20     {
21         if(!vis[i]) pri[++pl]=i,f[i]=f[i-1];
22         for(int j=1;j<=pl;j++)
23         {
24             if(pri[j]*i>Maxn-10) break;
25             vis[pri[j]*i]=1;
26             f[pri[j]*i]=f[pri[j]]+f[i];
27             if(i%pri[j]==0) break;
28         }
29     }
30 }
31 
32 int main()
33 {
34     init();
35     int T;
36     scanf("%d",&T);
37     while(T--)
38     {
39         int n,add=1;
40         scanf("%d",&n);
41         LL ans=0;
42         for(int i=1;i<=n;i++)
43         {
44             int p;LL q;
45             scanf("%d%lld",&p,&q);
46             if(p==2) add=0;
47             ans+=q*f[p];
48         }
49         printf("%lld\n",ans+add);
50     }
51     return 0;
52 }
View Code

 

2017-03-23 15:37:14

posted @ 2017-03-23 15:37  konjak魔芋  阅读(421)  评论(0编辑  收藏  举报