hdu6134 Battlestation Operational【2017多校第八场】

来源:互联网 发布:自学广告设计软件 编辑:程序博客网 时间:2024/05/24 06:57

转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents

题意

求f(n)mod109+7,(1n106)

f(n)=i=1nj=1iij[(i,j)=1]

where [(i,j)=1]evaluates to be 1 if gcd(i,j)=1, otherwise 0.

思路

f(n)=i=1nni[(n,i)=1]

g(n)=i=1nni

打表找规律能得到
g(n)=d|nf(d)

这个式子当时同学打表找规律得到的,等证明出来再来更新
然后由莫比乌斯反演我们可以得到
f(n)=d|nμ(nd)g(d)

现在问题转化成了怎么求g(n)
一种方法就是分段优化,对于每个n可以O(n)求出来,这样总体的复杂度就是O(nn),显然会超时。。。
下面介绍怎么正确求g(n)
递推法
g(n)=1+g(n1)+τ(n1)

关于这个递推式可以看一下这里
τ(x)表示x的因子个数
τ(x)这个函数可以O(nlogn)求出,这个和求因子和的过程差不多,具体可以看代码
然后就可以O(n)的求g(n),
然后就能O(nlogn)的求出f(n)了,这样就结束了
注:下面代码中的f(n)与g(n)正好与上面思路中相反


具体代码如下:
Result:Accepted   Memory: 30392K   Time : 374MS

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 1e6+5;const int mod = 1e9+7;ll sigma[maxn];ll f[maxn];ll g[maxn];ll tau[maxn];ll n,ans,cur;bool vis[maxn];int prime[maxn];int mu[maxn];int tot;void mobius(){    memset(vis,0,sizeof vis);    mu[1] = 1;    tot = 0;    for(int i=2;i<maxn;i++)    {        if( !vis[i] ){            prime[tot++] = i;            mu[i] = -1;        }        for(int j = 0; j < tot; j++)        {            if(i * prime[j] >=maxn) break;            vis[i * prime[j]] = true;            if( i % prime[j] == 0)            {                mu[i * prime[j]] = 0;                break;            }            else                mu[i * prime[j]] = -mu[i];        }    }}void init(){    mobius();    for(int i=1;i<maxn;i++)        for(int j=i;j<maxn;j+=i)            tau[j]++;    f[1] = 1;    for(int i=2;i<maxn;i++)        f[i] = 1+f[i-1]+tau[i-1];    for(int i=1;i<maxn;i++)        for(int j=i;j<maxn;j+=i)            g[j] = (g[j]+mu[j/i]*f[i]%mod+mod)%mod;    for(int i=2;i<maxn;i++)        g[i] = (g[i-1]+g[i])%mod;}int main(){    init();    while(~scanf("%lld",&n))        printf("%lld\n",g[n]);}
原创粉丝点击