题意

题意

求能用 $\frac{x}{y}(1\leq x\leq n,1\leq y\leq m)$ 表示的 $k$ 进制下纯循环小数个数 $n,m\leq 10^9,k\leq 2000$

题解

题意相当于 $\sum\limits_{1\leq x\leq n,1\leq y\leq m}[\gcd(x,y)=1][\gcd(y,k)=1]1$ ,考虑反演。

$$ \mathrm{lcm}(x,y)=\frac{xy}{\gcd(x,y)}=x\cdot\frac{y}{\gcd(x,y)}\\ \begin{align}&\sum_{1\leq x\leq n,1\leq y\leq m}[\gcd(x,y)=1][\gcd(y,k)=1]1\\ =&\sum_{1\leq x\leq n,y|k}\mu(x)\mu(y)\lfloor\frac{n}{x}\rfloor\lfloor\frac{m}{\mathrm{lcm}(x,y)}\rfloor\\ =&\sum_{1\leq x\leq n,y|k}\mu(x)\mu(y)\lfloor\frac{n}{x}\rfloor\lfloor\frac{\lfloor\frac{m}{x}\rfloor}{\frac{y}{\gcd(x,y)}}\rfloor\\ \end{align} $$

可以发现$x$确定的时候, $\mu(x),\lfloor\frac{n}{x}\rfloor,\lfloor\frac{m}{x}\rfloor$ 都是确定的,由于 $y|k$,$\frac{y}{\gcd(x,y)}$ 仅和 $\gcd(x,k),y$ 相关而不和 $x$ 相关。

对 $\lfloor\frac{n}{x}\rfloor,\lfloor\frac{m}{x}\rfloor$ 整除分块,则我们需要计算 $\sum\limits_{l\leq x\leq r}[\gcd(x,k)=y]\mu(x)$。

$$ g(n,k,y)=\sum_{1\leq x\leq n}[\gcd(x,k)=y]\mu(x)\\ f(n,k)=g(n,k,1)\\ g(n,k,y)=\mu(y)f(\lfloor\frac{n}{y}\rfloor,k)\\ f(n,k)=\sum_{x=1}^n\mu(x)-\sum_{i|k,i\not=1}g(n,k,i) $$

第二条正确性显然对吧,,,

第一条的话, 看上去应该是 $g(n,k,y)=\mu(y)f(\lfloor{\frac{n}{y}}\rfloor,\frac{k}{y})$。有可能的区别是 $k$ 某一种质因子,全都出现在 $y$ 中。如果有$\geq 2$个,那么已经 $\mu(y)=0$ 了。如果只有$1$个,那么再来一个质因子就直接 $=0$ 了,如果是 $\frac{k}{y}$ 就不会 $=0$ 所以这个式子就很合理。

$\mu$ 前缀和可以用杜教筛,$f$ 可以直接暴力,复杂度为$O(n^{\frac{1}{2}}d(k))$,预处理 $\leq n^{\frac{2}{3}}$ 的 $f$ 就是 $O(n^{\frac{1}{3}}d(k)+n^{\frac{2}{3}})$。

然后 $y$ 的部分,可以预处理每个 $x|k,\mu(x)\not=0,y|k$ 时的 $\frac{y}{\gcd(x,y)}$。

代码

/*
Author: QAQAutoMaton
Lang: C++
Code: cyclic.cpp
Mail: lk@qaq-am.com
Blog: https://www.qaq-am.com/
*/
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define int long long
#define debug(qaq...) fprintf(stderr,qaq)
#define DEBUG printf("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#define Debug debug("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#define all(x) x.begin(),x.end()
#define x first
#define y second
#define unq(a) sort(all(a)),a.erase(unique(all(a)),a.end())
using namespace std;
typedef unsigned uint;
typedef long long ll;
typedef unsigned long long ull;
typedef complex<double> cp;
typedef pair<int,int> pii;
int inf;
const double eps=1e-8;
const double pi=acos(-1.0);
template<class T,class T2>int chkmin(T &a,T2 b){return a>b?a=b,1:0;}
template<class T,class T2>int chkmax(T &a,T2 b){return a<b?a=b,1:0;}
template<class T>T sqr(T a){return a*a;}
template<class T,class T2>T mmin(T a,T2 b){return a<b?a:b;}
template<class T,class T2>T mmax(T a,T2 b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
template<class T>int dcmp(T a,T b){return a>b;}
template<int *a>int cmp_a(int x,int y){return a[x]<a[y];}
template<class T>bool sort2(T &a,T &b){return a>b?swap(a,b),1:0;}
#define min mmin
#define max mmax
#define abs aabs
struct __INIT__{
    __INIT__(){
        fill((unsigned char*)&inf,(unsigned char*)&inf+sizeof(inf),0x3f);
    }
}__INIT___;
namespace io {
    const int SIZE = (1 << 21) + 1;
    char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
    // getchar
    #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
    // print the remaining part
    inline void flush () {
        fwrite (obuf, 1, oS - obuf, stdout);
        oS = obuf;
    }
    // putchar
    inline void putc (char x) {
        *oS ++ = x;
        if (oS == oT) flush ();
    }
    template<typename A>
    inline bool read (A &x) {
        for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;else if(c==EOF)return 0;
        for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
        return 1;
    }
    inline bool read (char &x) {
        while((x=gc())==' '||x=='\n' || x=='\r');
        return x!=EOF;
    }
    inline bool read(char *x){
        while((*x=gc())=='\n' || *x==' '||*x=='\r');
        if(*x==EOF)return 0;
        while(!(*x=='\n'||*x==' '||*x=='\r'||*x==EOF))*(++x)=gc();
        *x=0;
        return 1;
    }
    template<typename A,typename ...B>
    inline bool read(A &x,B &...y){
        return read(x)&&read(y...);
    }
    template<typename A>
    inline bool write (A x) {
        if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;
        while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
        while (qr) putc (qu[qr --]);
        return 0;
    }
    inline bool write (char x) {
        putc(x);
        return 0;
    }
    inline bool write(const char *x){
        while(*x){putc(*x);++x;}
        return 0;
    }
    inline bool write(char *x){
        while(*x){putc(*x);++x;}
        return 0;
    }
    template<typename A,typename ...B>
    inline bool write(A x,B ...y){
        return write(x)||write(y...);
    }
    //no need to call flush at the end manually!
    struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: read;
using io :: putc;
using io :: write;

__gnu_pbds::gp_hash_table<int,int> mus,fs;
bitset<1000005>np,gg;
int k;
vector<int> d,dm;
int mu[1000005];
int smu[1000005],sf[1000005];
int pri[100005],ps;
const int w=1000000;
void init(){
    mu[1]=1;
    smu[1]=1;
    np[1]=1;
    for(int i=2;i<=w;++i){
        if(!np[i]){
            pri[++ps]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=ps && i*pri[j]<=w;++j){
            np[i*pri[j]]=1;
            if(i%pri[j])mu[i*pri[j]]=-mu[i];
            else{mu[i*pri[j]]=0;break;}
        }
        smu[i]=smu[i-1]+mu[i];
    }
    for(int i=1;i<=k;++i)if(!(k%i)){
        d.push_back(i);
        if(mu[i])dm.push_back(i);
    }
    for(auto i:dm)if(!np[i]){
        for(int j=i;j<=w;j+=i)gg[j]=1;
    }
    for(int i=1;i<=w;++i){
        sf[i]=sf[i-1];
        if(!gg[i])sf[i]+=mu[i];
    }
}
int s_mu(int n){
    if(n<=w)return smu[n];
    if(mus.find(n)!=mus.end())return mus[n];
    ll ans=1;
    for(ll l=2,r;l<=n;l=r+1){
        r=n/(n/l);
        ans=ans-(r-l+1)*s_mu(n/r);
    }
    return mus[n]=ans;
}
int f(int);
int g(int n,int d){
    return mu[d]*f(n/d);
}
int f(int n){
    if(n<=w){return sf[n];}
    if(fs.find(n)!=fs.end())return fs[n];
    int ans=s_mu(n);
    for(auto i:dm)if(i>1)ans-=g(n,i);
    return fs[n]=ans;
}
int v1[2005],s[2005][2005];
int lcm(int a,int b){return a/__gcd(a,b)*b;}
int solve(int l,int r,int w){
    for(int i=0;i<dm.size();++i)v1[i]=g(r,dm[i])-g(l-1,dm[i]);
    int ans(0);
    for(int i=0;i<dm.size();++i)for(int j=0;j<d.size();++j)ans+=mu[d[j]]*v1[i]*(w/s[i][j]);
    return ans;
}
signed main(){
#ifdef QAQAutoMaton 
    freopen("cyclic.in","r",stdin);
    freopen("cyclic.out","w",stdout);
#endif
    int n,m;
    read(n,m,k);
    init();
    for(int i=0;i<dm.size();++i)for(int j=0;j<d.size();++j)s[i][j]=lcm(dm[i],d[j])/dm[i];
    int ans(0);
    for(int l=1,r;l<=n && l<=m;l=r+1){
        r=min(n/(n/l),m/(m/l));
        ans+=(n/l)*solve(l,r,m/l);
    }
    write(ans,'\n');
    return 0;
}

标签: none

添加新评论