【bzoj 2749】: [HAOI2012]外星人

来源:互联网 发布:算法平台 编辑:程序博客网 时间:2024/05/02 02:01


http://www.lydsy.com/JudgeOnline/problem.php?id=2749


妈蛋官方数据是错的,害我查半天。。。。

留下个草稿或者说在线思路。。。。


my thoughts:


f(x)=0 (x=1)
f(x)=f(phi(x))+1 (else)


那么显然是可以O(n)求出来的


令k=i*prim[j]
f(1)=0
f(i)=f(i-1)+1 (i is a prime)
f(k)=f(phi(k))+1=f(phi(i)*prim[j])+1 (i%prim[j]==0)
f(k)=f(phi(k))+1=f(phi(i)*prim[j]-phi(i))+1 (else)
。。。。到此没啥思路


看看下面的提示
phi(p^q)=(p-1)*p^(q-1)


设x>2
则phi(x)必为偶数
每次变换一次必然消掉一些素因子,产生2
所以最后肯定是累积了大量的2


设g(x)为分解的过程中产生2的个数。。。


g(1)=0
g(2)=1


假设x为奇数
f(x)=g(x)+1


假设x为偶数
f(x)=g(x)


问题转化为如何求g(x)
g(1)=0
g(2)=1
g(2^q)=q
for p>2:
g(p)=g(p-1) (i is a prime)
g(p^q)=q*g(p-1)
g(p1p2)=g(p1)+g(p2) (phi是积性函数)


所以只需要考虑x<=10^5
发现最开始的时候我们已经解决了f(x),那么可以直接求g(x)


#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <cmath>#include <algorithm>using namespace std;#define rep(i,l,r) for(int i=(l),_=(r);i<=_;i++)#define per(i,r,l) for(int i=(r),_=(l);i>=_;i--)#define MS(arr,x) memset(arr,x,sizeof(arr))#define INE(i,u) for(int i=head[u];~i;i=e[i].next)#define LL long longinline const int read(){int r=0,k=1;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';return k*r;}////////////////////////////////////////////////const int N=100010;int prim[N],f[N],phi[N],cnt;bool flag[N];int g[N];////////////////////////////////////////////////void init(){f[1]=0;rep(i,2,100000){if(!flag[i]) prim[++cnt]=i,phi[i]=i-1,f[i]=f[i-1]+1;for(int j=1;i*prim[j]<=100000&&j<=cnt;j++){int k=i*prim[j];flag[k]=1;if(i%prim[j]==0){phi[k]=phi[i]*prim[j];break;}phi[k]=phi[i]*(prim[j]-1);}}rep(i,2,100000) f[i]=f[phi[i]]+1;g[1]=0;g[2]=1;rep(i,3,100000){if(i&1) g[i]=f[i]-1;else g[i]=f[i];}}////////////////////////////////////////////////void input(){    }void solve(){init();    rep(i,1,read())    {    int n=read();    LL ans=0;    bool flag=0; //是否为偶数     rep(i,1,n)    {    int p=read(),q=read();    if(p==1) continue;    if(p==2)    {    flag=1;    ans+=q;    }    else    {    ans+=(LL)q*g[p-1];    }    }    if(!flag) ans++;    printf("%lld\n",ans);    }}////////////////////////////////////////////////int main(){    freopen("_.in","r",stdin); freopen("_.out","w",stdout);    input(),solve();    return 0;}


0 0