bzoj4176 Lucas 的数论

======i=1nj=1nf(ij)i=1nj=1nd=1n2[dgcd(i,d)|j]i=1nd=1n2ngcd(i,d)dd=1ni=1ndj=1n2dnje(gcd(i,j))d=1ni=1ndj=1nnjx|gcd(i,j)μ(x)x=1nμ(x)d=1nndxj=1nxnjxx=1nμ(x)(j=1nxnjx)2

对后面的部分进行下底函数分块,一段 μ(x) 的和用杜教筛求出。

#include
#include
using namespace std;
#define LL long long
const int maxn=3000000,p=1000007,mod=1000000007,oo=0x3f3f3f3f;
struct hash_table
{
    int fir[p+10],ne[maxn],val[maxn],ans[maxn],tot;
    int find(int n)
    {
        for (int i=fir[n%p];i;i=ne[i])
            if (val[i]==n) return ans[i];
        return oo;
    }
    void ins(int n,int x)
    {
        int y=n%p;
        tot++;
        ne[tot]=fir[y];
        fir[y]=tot;
        val[tot]=n;
        ans[tot]=x;
    }
}h;
int inc(int x,int y)
{
    x+=y;
    return x>=mod?x-mod:x;
}
int dec(int x,int y)
{
    x-=y;
    return x<0?x+mod:x;
}
int summu(int n)
{
    if (!n) return 0;
    int ret=h.find(n);
    if (ret!=oo) return ret;
    ret=1;
    for (int i=2,j;i<=n;i=j+1)
    {
        j=n/(n/i);
        ret-=(j-i+1)*summu(n/i);
    }
    h.ins(n,ret);
    return ret;
}
int sumdiv(int n)
{
    int ret=0;
    for (int i=1,j;i<=n;i=j+1)
    {
        j=n/(n/i);
        ret=inc(ret,(LL)(j-i+1)*(n/i)%mod);
    }
    return ret;
}
int main()
{
    int n,x,y,ans=0;
    scanf("%d",&n);
    //n=1000000000;
    for (int i=1,j;i<=n;i=j+1)
    {
        j=n/(n/i);
        x=dec(summu(j),summu(i-1));
        y=sumdiv(n/i);
        ans=inc(ans,(LL)x*y%mod*y%mod);
    }
    printf("%d\n",ans);
}

你可能感兴趣的:(数学,bzoj)