[BZOJ4652][Noi2016]循环之美:莫比乌斯反演+杜教筛

orz:http://www.cnblogs.com/lcf-2000/p/6250330.html

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <utility>
#include <map>
#define Mp make_pair
using namespace std;
typedef long long LL;
typedef pair<int,int> Pii;
const int MAXN=10000005;
int n,m,k,cnt,prm[MAXN>>3],mo[MAXN],f[2005],d[2005],top;
bool vis[MAXN];
map<Pii,int> g;
int gcd(int x,int y){
    while(y){
        swap(x,y);
        y%=x;
    }
    return x;
}
void pre_process1(){
    mo[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]){
            prm[++cnt]=i;
            mo[i]=-1;
        }
        for(int j=1;j<=cnt&&i*prm[j]<=n;j++){
            vis[i*prm[j]]=1;
            if(i%prm[j]==0){
                mo[i*prm[j]]=0;
                break;
            }
            mo[i*prm[j]]=-mo[i];
        }
    }
    for(int i=1;i<=n;i++)
        mo[i]+=mo[i-1];
}
void pre_process2(){
    for(int i=1;i<=k;i++)
        f[i]=f[i-1]+(gcd(i,k)==1);
    for(int i=1;prm[i]<=k;i++)
        if(k%prm[i]==0) d[++top]=prm[i];
}
int getf(int x){
    return (x/k)*f[k]+f[x%k];
}
int getg(int x,int y){
    if(x==0) return 0;
    if(x==1) return 1;
    Pii now=Mp(x,y);
    if(y==0){
        if(x<=MAXN-5) return mo[x];
        if(g.count(now)) return g[now];
        int ans=1,nxti;
        for(int i=2;i<=x;i=nxti){
            nxti=x/(x/i)+1;
            ans-=(nxti-i)*getg(x/i,0);
        }
        return g[now]=ans;
    }
    if(g.count(now)) return g[now];
    return g[now]=getg(x,y-1)+getg(x/d[y],y);
}
int main(){
    n=MAXN-5;
    pre_process1();
    scanf("%d%d%d",&n,&m,&k);
    pre_process2();
    LL ans=0;int nxti;
    int lim=min(n,m);
    for(int i=1;i<=lim;i=nxti){
        nxti=min(n/(n/i),m/(m/i))+1;
        ans+=1ll*(n/i)*getf(m/i)*(getg(nxti-1,top)-getg(i-1,top));
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9498772.html
今日推荐