首页 > 其他 > 详细

[HAOI2012]外星人

时间:2019-10-15 19:27:46      阅读:80      评论:0      收藏:0      [点我收藏+]

题意

给一个数N,求它经过多少次取\(phi\)可以变成1

思路

由于只有\(\varphi_{1}\)\(\varphi_{2}\)为1,所以原数变成1的过程必经2,由

\[\varphi(\prod_{i = 1}^m p_i^{q_i}) = \prod_{i = 1}^m (p_i - 1)*p_i^{q_i-1}\]

可知一次操作只能消掉一个2,所以可以通过求出2的个数来求操作次数

\(f_i\)表示\(i\)变成1的过程中会生成的2的个数,有以下性质:

\(i\)为质数时,\(f_i=f_{i-1}\),即质数\(i\)\(i-1\)生成的2个数相同

\(i\)不为质数时,\(f_i=f_a*f_b ,(a*b=i)\),即两数互不干扰,这里利用这个性质将原数质因数分解即可

对于\(n=\prod{p_{i}^{q_{i}}}\),有\(ans=\prod{f_{p_i}*q_i}\)

之所以用2的个数表示答案,是因为假设一次操作消一个2,但如果一开始\(n\)没有2,就需要额外的一步来生成2

Code

#include<bits/stdc++.h>
#define N 100005
using namespace std;
typedef long long ll;
int T,n;
int p[N],isnotp[N],cnt;
ll f[N];

template <class T>
void read(T &x)
{
    char c;int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}
void init(int maxn)
{
    f[1]=1;
    isnotp[1]=1;
    for(int i=2;i<=maxn;++i)
    {
        if(!isnotp[i]) p[++cnt]=i,f[i]=f[i-1];
        for(int j=1;j<=cnt&&(ll)p[j]*i<=maxn;++j)
        {
            isnotp[p[j]*i]=1;
            f[p[j]*i]=f[p[j]]+f[i];
            if(i%p[j]==0) break;
        }
    }
}
int main()
{
    init(N-5);
    read(T);
    while(T--)
    {
        read(n);
        ll ans=0,flag=1;
        for(int i=1;i<=n;++i)
        {
            int p,c;
            read(p);read(c);
            if(p==2) flag=0;
            ans+=f[p]*c;
        }
        printf("%lld\n",ans+flag);
    }
    return 0;
}

[HAOI2012]外星人

原文:https://www.cnblogs.com/Chtholly/p/11679609.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!