NOIP提高组【JZOJ4782】Math

来源:互联网 发布:股票价值计算软件 编辑:程序博客网 时间:2024/05/21 08:00

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

考虑到是(1)mj=1d(ij),所以我们要考虑mj=1d(ij)的奇偶性。很显然,只有当i* j为完全平方数时,d(i* j)Mod2才为1,其余Mod2后都为0。我们分解质因数设i=ap11ap22…… apkk,设p表示当p*i使p *i为完全平方数时,p最小的值为多少。我们设p=ab11ab22…… abkk那么显然p要使每一个p[i]+b[i]均为偶数,且b[i]尽量小。所以,当p[i]为奇数时,b[i]就为1,当p[i]为偶数时,b[i]就为0。那么我们就可以很快算出p的值了。

得到p后,我们考虑要怎样的j才时i*j为完全平方数。那么显然j=p*q2,q为任意数且p*q2<=m。那么我们可以发现q的取值个数为m/p。所以,我们只要判断一下m/p的奇偶性。m/p为奇数则答案+1,否则答案-1。那么,这道题我们就可以用O(N*N)的时间看似解决了。

但其实,这会超时……(N<=107)。

问题就出在计算p上。我们要计算一个数的的指数为奇数的的质因子的连乘时是O(N)的。所以我们必须用更高级的算法!

对,就是线性筛。

设一个数i的指数为奇数的质因子的连乘是f[i],那么对于一个质数,它的f值显然是i。那么对于一个i*d[k] (d[k]表示小于等于i的质数),当i不是d[k]的倍数时,表明i中不含有d[k]这个因子,那么f[i *d[k]]显然等于f[i] *d[k]。当i是d[k]的倍数时,我们还要考虑f[i]中是否已经含有d[k]。(因为不是i是d[k]的倍数并不能说明d[k]在i中的指数为奇数!)假设f[i]中已经含有d[k],那么f[i *d[k]]中则要把d[k]删去,即f[i *d[k]]=f[i]/d[k],否则f[i *d[k]]中则要把d[k]加上,即f[i *d[k]]=f[i] *d[k]。

最后O(N)扫一遍f统计一下答案即可。总时间复杂度为O(N)。(看起来解释很复杂,其实代码很短的……)

代码

#include<iostream>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define ll long longusing namespace std;const int maxn=10000007;int f[maxn],n,i,t,j,k,l,x,y,z;ll m,d[maxn],p,ans;bool bz[maxn],bz1;int main(){//  freopen("data.in","r",stdin);    scanf("%d%lld",&n,&m);    f[1]=1;    for (i=2;i<=n;i++){        if (!bz[i]) d[++d[0]]=i,f[i]=i;        for (k=1;k<=d[0];k++){            if (i*d[k]>n) break;bz[i*d[k]]=true;            if (i%d[k]) f[i*d[k]]=f[i]*d[k];            else{                if (f[i]%d[k])f[i*d[k]]=f[i]*d[k];                else f[i*d[k]]=f[i]/d[k];                break;            }        }    }    for (i=1;i<=n;i++){        t=sqrt(m/f[i]);        if (t%2) ans--;        else ans++;    }    printf("%d\n",ans);}
3 0