当前位置: 代码迷 >> 综合 >> 数论·欧拉函数·[HAOI2012]外星人
  详细解决方案

数论·欧拉函数·[HAOI2012]外星人

热度:65   发布时间:2023-12-16 11:27:19.0

[HAOI2012]外星人

题目大意:给定一个数N,问你这个数取多少次欧拉函数后变成1
题目类型:欧拉函数

Input
test(数据数量),每组一个m,接下来m个pi,qi,为n的标准分解形式

Output

输出test行整数

Sample Input

1 2
2 2
3 1

Sample Output

3

题解

注意到只有phi[2]=1,所以每个数最终都是要经过phi[2]=1这一步变为1

而每一次做欧拉函数,根据欧拉函数的计算式可以看出:会产生一个2,也必会消掉一个2. 每个pi做一次欧拉函数,就变成了pi-1,而pi减1必为合数,除非pi为2,pi-1又分解为若干个pi的qi次方,继续下去,直到pi为2,结束,则有多少个2,就需要多少次。 因此我们只需要算出原数N的质因子一共会产生多少个2即可 于是我们令f[i]表示i分解出了几个2: i为质数,f[i] = f[i - 1];否则,f[i * prime[j] = f[i] + f[prime[j]]
另:如果一开始n为奇数,则ans需+ 1,因为变出2需要第一步。 因为若开始是奇数,第一次做欧拉函数是不会消掉2的,且运作到中间不会出现没有2的情况,因为pi为奇数,pi-1则必定为偶数,2一定会有的。

代码

    #include<bits/stdc++.h>typedef long long ll;using namespace std;const ll M = 1e5+10;ll f[M], prime[M/2],cnt = 0,test;bool check[M];void make_prime(){
    f[1] = 1;for(ll i = 2; i <= M; i++){
    if(!check[i]) prime[++cnt] = i,f[i] = f[i - 1];for(ll j = 1; j <= cnt && i * prime[j] <= M; j++){
    check[i * prime[j]] = 1;f[i * prime[j]] = f[i] + f[prime[j]];if(i%prime[j] == 0) break;}}}int main(){
    // freopen("alien.in","r",stdin);// freopen("alien.out","w",stdout);scanf("%lld",&test);make_prime();while(test--){
    ll ans = 1,m,pi,qi;scanf("%lld",&m);for(ll i = 1; i <= m;i++){
    scanf("%lld%lld",&pi,&qi);if(pi == 2) ans--;ans += f[pi] * qi;}printf("%lld\n",ans);}return 0;}