BZOJ 2005 NOI2010 能量采集 莫比乌斯反演

来源:互联网 发布:react.js项目 编辑:程序博客网 时间:2024/06/02 05:41

BZOJ又被卡了

这里写图片描述


这道题水过,作为第一道莫比乌斯反演的习题,我还是理解了好长时间分块的想法的,可能是我太菜了吧…


首先一个推导我们需要求的是

i=0nj=0m(gcd(i,j)21)

进行推导
=2i=0nj=0m(gcd(i,j))nm

n=d|nφ(d),ngcd(i,j),

=2i=0nj=0md|gcd(i,j)φ(d)nm

=2i=0nj=0md=1n[d|i][d|j]φ(d)nm

=2d=1ni=0n[d|i]j=0m[d|j]φ(d)nm

=2d=1nn/dm/dφ(d)nm

一组询问可以O(n)水过去,多组询问就分块搞
注意其中有一步,是直接把d转换到1到n了,其实这里有个取较小值操作,我们可以把n当作小的那个,然后来搞


#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int MAXN=100000+50;long long n,m,is_not_prime[MAXN],phi[MAXN],prime[MAXN];inline void getphi(){    phi[1]=1;    for(register int i=2;i<=n;i++){        if(!is_not_prime[i]){            prime[++prime[0]]=i;            phi[i]=i-1;        }        for(register int j=1;j<=prime[0]&&i*prime[j]<=n;j++){            is_not_prime[i*prime[j]]=1;            if(i%prime[j]==0){                phi[i*prime[j]]=prime[j]*phi[i];                break;            }else{                phi[i*prime[j]]=phi[i]*(prime[j]-1);            }         }        phi[i]+=phi[i-1];    }}int main(){    scanf("%lld%lld",&n,&m);    if(n<m) swap(n,m);    getphi();    long long end,final=0;    for(register long long start=1;start<=m;start=end+1){        end=min(n/(n/start),m/(m/start));        final+=(phi[end]-phi[start-1])*(n/start)*(m/start);    }    printf("%lld\n",final*2-m*n);    return 0;}

这里写图片描述

阅读全文
0 0
原创粉丝点击