「欧拉函数」bzoj 2749 & haoi 2012 外星人

题目大意

给定一个数的标准分解形式,求这个数经过多少次$varphi$函数会变成$1$。

  • 数据范围:$T leqslant 50,p_i leqslant10^5,1leqslant q_ileqslant 10^9$

样例

Input

1
2
3
4
1
2
2 2
3 1

Output

1
3

Solution

根据我们的观察,我们发现只有$varphi(2) = 1$,

由于$varphi(prod p_i^{q_i}) =prod (p - 1)(p^{q_i - 1})$,所以我们每求一次欧拉函数就会消掉一个$2$,同时每个质因子又会昌产生若干个$2$,

所以我们只需要算出每个质因子进过一次欧拉函数后会产生多少个$2$即可

设$f(i)$表示$i$分解出的$2$的个数,然后随手经过严谨的思考后写出$f$的递推式。
这时,线性筛的$mathfrak{NB}$之处就显示出来了,嗯哼?

Code

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

#include <set>
#include <ctime>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
#include <bitset>
#include <cstdio>
#include <cctype>
#include <string>
#include <numeric>
#include <cstring>
#include <cassert>
#include <climits>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std ;
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define loop(v, it) for (auto it = v.begin(); it != v.end(); it++)
#define cont(i, x) for (int i = head[x]; i; i = e[i].nxt)
#define clr(a) memset(a, 0, sizeof(a))
#define ass(a, sum) memset(a, sum, sizeof(a))
#define lowbit(x) (x & -x)
#define all(x) x.begin(), x.end()
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define iv inline void
#define enter cout << endl
#define siz(x) ((int)x.size())
#define P(x) putchar(48 + x)
typedef long long ll ;
typedef unsigned long long ull ;
typedef double db ;
typedef pair <ll, ll> pii ;
typedef vector <ll> vi ;
typedef vector <pii> vii ;
typedef queue <ll> qi ;
typedef set <ll> si ;
typedef map <ll, ll> mii ;
typedef map <string, ll> msi ;
const ll maxn = 1e5 + 5 ;
const ll inf = 0x3f3f3f3f ;
const ll iinf = 1 << 30 ;
const ll linf = 2e18 ;
const ll mod = 1e9 ;
const db eps = 1e-16;
void (int x) { cout << x << endl ; exit(0) ; }
void PRINT(string x) { cout << x << endl ; exit(0) ; }
void douout(double x){ printf("%lfn", x + 0.0000000001) ; }

ll T,n,p,q,cnt,ans;

ll prime[maxn],f[maxn];

bool check[maxn];

void init()
{
f[1] = 1;
for(int i = 2;i < maxn; ++i)
{
if(!check[i]) prime[++cnt] = i,f[i] = f[i - 1];
for(int j = 1;j <= cnt && prime[j] * i < maxn; ++j)
{
check[i * prime[j]] = 1;
f[i * prime[j]] = f[i] + f[prime[j]];
if(i % prime[j] == 0) break;
}
}
}

int main()
{
init();
scanf("%lld",&T);
while(T--)
{
ans = 1;
scanf("%lld",&n);
while(n--)
{
scanf("%lld",&p);
scanf("%lld",&q);
ans += f[p] * q;
if(p == 2) ans--;
}
printf("%lldn",ans);
}
}