UOJ Logo zhouzixuan的博客

博客

bzoj 3561: DZY Loves Math VI

2015-12-31 22:17:44 By zhouzixuan
【题目描述】:

【题目解法】:
    枚举d=gcd(i,j)
    ans=sigma(d^d*sigma(i^d)*sigma(j^d)*sigma(mu(k))) 1<=i<=n/d  1<=j<=m/d  k|i且k|j
    ans=sigma(d^d*sigma(mu(k)*sigma(i^d)*sigma(j^d)*k^d*k^d))  1<=k<=n/d  1<=i<=n/kd  1<=j<=m/kd1
    然后我们O(N)枚举d,然后O(N/d)枚举k并且计算sigma(i^d),然后就可以O(1)的到后面的答案
    合并即可,复杂度O(N log N)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=500005;
const long long maxmod=1000000007;
int n,m,mobius[N],tot,prime[N];
bool v[N]; long long val[N],sum[N],ans;
inline long long getint()
{
    long long x=0; char c=getchar(); bool flag=false;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') flag=true,c=getchar();
    while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
    if (flag) return -x; else return x;
}
void init()
{
    n=getint(); m=getint(); if (n>m) swap(n,m);
    memset(v,true,sizeof(v)); mobius[1]=1;
    for (int i=2; i<=n; i++)
    {
        if (v[i]) prime[++tot]=i,mobius[i]=-1;
        for (int j=1; j<=tot; j++)
        {
            if (i*prime[j]>n) break; v[i*prime[j]]=false;
            mobius[i*prime[j]]=-mobius[i];
            if (i%prime[j]==0) {mobius[i*prime[j]]=0; break;}
        }
    }
}
inline long long calc(long long x,long long y)
{
    long long nowans=1;
    while (y)
    {
        if (y%2==1) nowans=nowans*x%maxmod;
        x=x*x%maxmod; y=y/2;
    }
    return nowans;
}
void solve()
{
    for (int i=1; i<=m; i++) val[i]=1;
    for (int i=1; i<=n; i++)
    {
        for (int j=1; j<=m/i; j++) val[j]=val[j]*j%maxmod;
        for (int j=1; j<=m/i; j++) sum[j]=(sum[j-1]+val[j])%maxmod;
        long long nowans=0;
        for (int j=1; j<=n/i; j++)
        {
            long long tmp=val[j]*val[j]%maxmod*sum[n/i/j]%maxmod*sum[m/i/j]%maxmod;
            nowans=nowans+mobius[j]*tmp%maxmod; nowans=(nowans%maxmod+maxmod)%maxmod;
        }
        nowans=nowans*calc(i,i)%maxmod;
        ans=(ans+nowans)%maxmod;
    }
    printf("%lld\n",ans);
}
int main()
{
    init();
    solve();
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。