bzoj2005: [Noi2010]能量采集

感觉莫反学的很不扎实。。很虚。。bs lmy

为什么这么说,是因为我连求F(i)要把他转换成F(1)再求都不知道。。。。

 

那么这题抽象点看ans就是等于这个

ans = n*m + sigema(1~n)x sigema(1~m)y (gcd(x,y)-1)*2

F(i)表示 gcd(x,y)==i 的个数,那么ans = n*m + sigema(1~n)i (n-1)*2*F(i)

G(i)表示 gcd(x,y)==i的倍数 的个数

那么G(i)=(n/i)*(m/i)

然后反演形式2 F(i)=sigma(u(d/i)*G(d)) (其中n|d)

 

PS(无脑long long)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;

LL pr,prime[110000],u[110000];
bool v[110000];
void mobius_inversion()
{
    pr=0;u[1]=1;
    memset(v,true,sizeof(v));
    for(int i=2;i<=100000;i++)
    {
        if(v[i]==true)
        {
            prime[++pr]=i;
            u[i]=-1;
        }
        for(int j=1;j<=pr&&i*prime[j]<=100000;j++)
        {
            v[i*prime[j]]=false;
            if(i%prime[j]==0){u[i*prime[j]]=0;break;}
            u[i*prime[j]]=-u[i];
        }
        u[i]+=u[i-1];
    }
}

LL getFi(LL n,LL m)
{
    LL t=min(n,m),last;LL Fi=0;
    for(LL d=1;d<=t;d=last+1)
    {
        last=min(n/(n/d),m/(m/d));
        LL Gd=(n/d)*(m/d);
        Fi+=(u[last]-u[d-1])*Gd;
    }
    return Fi;
}
int main()
{
    mobius_inversion();
    
    LL n,m;
    scanf("%lld%lld",&n,&m);
    if(n>m)swap(n,m);
    
    LL ans=n*m;
    for(int i=1;i<=n;i++)
    {
        ans+=(i-1)*2*getFi(n/i,m/i);
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2017-11-27 14:03  AKCqhzdy  阅读(...)  评论(...编辑  收藏