[NOI2016]循环之美

题意:求 nx=1my=1xy ∑ x = 1 n ∑ y = 1 m x y k k 进制下能表示成循环节从第一位小数开始的无限循环小数或整数的最简分数个数

假设xy的循环节长度为 l l

[xkly]=[xy]

这里中括号表示其小数部分,意思就是把小数点往后挪 l l 位,小数部分还是相同

比如1.123123小数点往后挪3位变成 1123.123 1123.123 …

参照10进制下小数点往后挪 l l 位就是乘以10l

那么 k k 进制下小数点往后挪l位就是乘以 kl k l

xklyxkly=xyxy ⇒ x k l y − ⌊ x k l y ⌋ = x y − ⌊ x y ⌋

xklxklyy=xxyy ⇒ x k l − ⌊ x k l y ⌋ ∗ y = x − ⌊ x y ⌋ ∗ y

xklxmody ⇒ x k l ≡ x mod y

题目要求最简分数,所以 (x,y)=1 ( x , y ) = 1

kl1mody ⇒ k l ≡ 1 mod y

(k,y)=1 ⇒ ( k , y ) = 1

Ans=ni=1mj=1[(i,j)=1][(j,k)=1] ⇒ A n s = ∑ i = 1 n ∑ j = 1 m [ ( i , j ) = 1 ] [ ( j , k ) = 1 ]

那么接下来就有两条路可以走了

一:考虑处理 [(i,j)=1] [ ( i , j ) = 1 ]

(有公式恐惧症下转法二)

ni=1mj=1[(i,j)=1][(j,k)=1] ∑ i = 1 n ∑ j = 1 m [ ( i , j ) = 1 ] [ ( j , k ) = 1 ]

=mj=1[(j,k)=1]ni=1[(i,j)=1] = ∑ j = 1 m [ ( j , k ) = 1 ] ∑ i = 1 n [ ( i , j ) = 1 ]

=mj=1[(j,k)=1]ni=1d|(i,j)μ(d) = ∑ j = 1 m [ ( j , k ) = 1 ] ∑ i = 1 n ∑ d | ( i , j ) μ ( d )

=mj=1[(j,k)=1]ni=1d|i,d|jμ(d) = ∑ j = 1 m [ ( j , k ) = 1 ] ∑ i = 1 n ∑ d | i , d | j μ ( d )

=mj=1[(j,k)=1]nd|jμ(d)nd = ∑ j = 1 m [ ( j , k ) = 1 ] ∑ d | j n μ ( d ) n d

=nd=1μ(d)ndmj=1[d|j][(j,k)=1] = ∑ d = 1 n μ ( d ) n d ∑ j = 1 m [ d | j ] [ ( j , k ) = 1 ]

=nd=1μ(d)ndmjd=1[d|jd][(jd,k)=1] = ∑ d = 1 n μ ( d ) n d ∑ j d = 1 m [ d | j d ] [ ( j d , k ) = 1 ]

j j jd替换一下来减少限制(下同)

=nd=1μ(d)ndmdj=1[(jd,k)=1] = ∑ d = 1 n μ ( d ) n d ∑ j = 1 m d [ ( j d , k ) = 1 ]

=nd=1μ(d)[(d,k)=1]ndmdj=1[(j,k)=1] = ∑ d = 1 n μ ( d ) [ ( d , k ) = 1 ] n d ∑ j = 1 m d [ ( j , k ) = 1 ]

考虑 f(n)=ni=1[(i,k)=1]=nkϕ(k)+f(nmodk) f ( n ) = ∑ i = 1 n [ ( i , k ) = 1 ] = n k ϕ ( k ) + f ( n mod k )

暴力 O(klogk)gcd O ( k log ⁡ k ) gcd 算一下 f(1)f(k) f ( 1 ) … f ( k )

接下来貌似又有两条路可以走了

①:考虑化简式子

考虑 g(n,k)=nd=1μ(d)[(d,k)=1] g ( n , k ) = ∑ d = 1 n μ ( d ) [ ( d , k ) = 1 ]

=nd=1μ(d)p|(d,k)μ(p) = ∑ d = 1 n μ ( d ) ∑ p | ( d , k ) μ ( p )

=nd=1μ(d)p|d,p|kμ(p) = ∑ d = 1 n μ ( d ) ∑ p | d , p | k μ ( p )

=nd=1p|dμ(d)p|kμ(p) = ∑ d = 1 n ∑ p | d μ ( d ) ∑ p | k μ ( p )

=p|kμ(p)ndp=1p|dpμ(dp) = ∑ p | k μ ( p ) ∑ d p = 1 n ∑ p | d p μ ( d p )

=p|kμ(p)npd=1μ(dp) = ∑ p | k μ ( p ) ∑ d = 1 n p μ ( d p )

如果 (d,p)1 ( d , p ) ≠ 1 ,那么 μ(dp)=0 μ ( d p ) = 0

=p|kμ(p)npd=1μ(dp)[(d,p)=1] = ∑ p | k μ ( p ) ∑ d = 1 n p μ ( d p ) [ ( d , p ) = 1 ]

=p|kμ(p)npd=1μ(d)μ(p)[(d,p)=1] = ∑ p | k μ ( p ) ∑ d = 1 n p μ ( d ) μ ( p ) [ ( d , p ) = 1 ]

=p|kμ(p)2npd=1μ(d)[(d,p)=1] = ∑ p | k μ ( p ) 2 ∑ d = 1 n p μ ( d ) [ ( d , p ) = 1 ]

=p|kμ(p)2g(np,p) = ∑ p | k μ ( p ) 2 g ( n p , p )

边界 g(0,k)=0 g ( 0 , k ) = 0

g(n,1)=nd=1μ(d) g ( n , 1 ) = ∑ d = 1 n μ ( d ) 直接杜教筛

复杂度是 O O ((k的质因子个数) n+n23 n + n 2 3 )

#include<map>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define fp(i,a,b) for(int i=a,I=b;i<=I;++i)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
const int N=7e5+5,E=2e6+5;
typedef int arr[N];typedef long long ll;
struct Am{int nx,x,w;}e1[E];
struct Ans{int nx,n,m,k;ll w;}e2[E];
int n,m,k,M,c1,c2,K[2000],f1[E],f2[E];arr is,pr,mu,Smu;
int Sm(int x){
    if(x<=M)return Smu[x];
    int u=(x+2017)%E;
    for(int i=f1[u];i;i=e1[i].nx)if(e1[i].x==x)return e1[i].w;
    e1[++c1]=Am{f1[u],x,1};f1[u]=c1;
    int&w=e1[c1].w,i=2,j=sqrt(x);
    for(;i<=j;++i)w-=Sm(x/i);
    for(;i<=x;i=j+1)j=x/(x/i),w-=(j-i+1)*Sm(x/i);
    return w;
}
ll sol(int n,int m,int k){
    if(!n||!m)return 0;
    int u=(2017ll*n+m+k)%E;
    for(int i=f2[u];i;i=e2[i].nx)if(e2[i].n==n&&e2[i].m==m&&e2[i].k==k)return e2[i].w;
    e2[++c2]=Ans{f2[u],n,m,k,0};f2[u]=c2;ll&w=e2[c2].w;
    if(k==1){
        if(n>m)swap(n,m);
        int i=1,j=sqrt(n),s,t=0,x,y;
        for(;i<=j;++i,t=s)s=Sm(i),w+=1ll*(n/i)*(m/i)*(s-t);
        for(;i<=n;i=j+1,t=s)x=n/i,y=m/i,j=min(n/x,m/y),s=Sm(j),w+=1ll*x*y*(s-t);
        u=(2017ll*m+n+k)%E;e2[++c2]=Ans{f2[u],m,n,k,w};f2[u]=c2;
    }else for(int i=1;i<=K[0]&&K[i]<=k;++i)
            if(k%K[i]==0&&mu[K[i]])
                w+=sol(m/K[i],n,K[i])*mu[K[i]];
    return w;
}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    scanf("%d%d%d",&n,&m,&k);
    M=min(N-5,max(k,min(n,m)));Smu[1]=mu[1]=1;
    fp(i,2,M){
        if(!is[i])pr[++pr[0]]=i,mu[i]=-1;
        for(int j=1,x;j<=pr[0]&&(x=i*pr[j])<=M;++j){
            is[x]=1;if(i%pr[j])mu[x]=-mu[i];else break; 
        }Smu[i]=Smu[i-1]+mu[i];
    }
    fp(i,1,k)if(k%i==0)K[++K[0]]=i;
    printf("%lld",sol(n,m,k));
return 0;
}
②:考虑分析式子

我们可以把 k k 表示成paq,假设 p p k最小的质因子

对于1到 k k 中每一个数可以预处理出他的p,q

g(n,k)=nd=1μ(d)[(d,k)=1]=nd=1μ(d)[(d,p)=1][(d,q)=1] g ( n , k ) = ∑ d = 1 n μ ( d ) [ ( d , k ) = 1 ] = ∑ d = 1 n μ ( d ) [ ( d , p ) = 1 ] [ ( d , q ) = 1 ]

(d,q)=1 ( d , q ) = 1 时只有 (d,p)=1,(d,p)=p ( d , p ) = 1 , ( d , p ) = p 两种情况

所以我们可以转化为求满足 (d,q)=1 ( d , q ) = 1 μ(d) μ ( d ) 减去 (d,q)=1 ( d , q ) = 1 中满足 (d,p)=p ( d , p ) = p μ(d) μ ( d )

g(n,k)=nd=1μ(d)[(d,q)=1]nd=1μ(d)[(d,q)=1][(d,p)=p] g ( n , k ) = ∑ d = 1 n μ ( d ) [ ( d , q ) = 1 ] − ∑ d = 1 n μ ( d ) [ ( d , q ) = 1 ] [ ( d , p ) = p ]

=g(n,q)ndp=1μ(dp)[(dp,q)=1][(dp,p)=p] = g ( n , q ) − ∑ d p = 1 n μ ( d p ) [ ( d p , q ) = 1 ] [ ( d p , p ) = p ]

=g(n,q)npd=1μ(dp)[(d,q)=1] = g ( n , q ) − ∑ d = 1 n p μ ( d p ) [ ( d , q ) = 1 ]

(d,p)1 ( d , p ) ≠ 1 μ(dp)=0 μ ( d p ) = 0 ,所以 d d 要满足(d,p)=1

=g(n,q)npd=1μ(dp)[(d,p)=1][(d,q)=1] = g ( n , q ) − ∑ d = 1 n p μ ( d p ) [ ( d , p ) = 1 ] [ ( d , q ) = 1 ]

=g(n,q)npd=1μ(d)μ(p)[(d,k)=1] = g ( n , q ) − ∑ d = 1 n p μ ( d ) μ ( p ) [ ( d , k ) = 1 ]

=g(n,q)μ(p)npd=1μ(d)[(d,k)=1] = g ( n , q ) − μ ( p ) ∑ d = 1 n p μ ( d ) [ ( d , k ) = 1 ]

=g(n,q)+g(np,k) = g ( n , q ) + g ( n p , k )

边界和复杂度是同上

#include<cmath>
#include<cstdio>
#include<algorithm>
#define fp(i,a,b) for(int i=a,I=b;i<=I;++i)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
const int N=1e6+5,E=2.2*N;
typedef int arr[N];
struct eg{int nx,n,k,w;}e[E];
int n,m,k,M,ce,fi[E],p[2001],q[2001];arr is,pr,mu,Smu,f;
int g(int n,int k){
    if(!n||(n<=M&&k==1))return Smu[n];
    int x=(1LL*n*2017+k)%E;
    for(int i=fi[x];i;i=e[i].nx)if(e[i].n==n&&e[i].k==k)return e[i].w;
    e[++ce]=eg{fi[x],n,k,0};fi[x]=ce;int&w=e[ce].w;
    if(k==1){
        w=1;int i=2,j=sqrt(n),x;
        for(;i<=j;++i)w-=g(n/i,1);
        for(;i<=n;i=j+1)x=n/i,j=n/x,w-=(j-i+1)*g(x,1);
    }else w=g(n,q[k])+g(n/p[k],k);
    return w;
}
int gcd(int a,int b){return!b?a:gcd(b,a%b);}
inline int Sf(int x){return x/k*f[k]+f[x%k];}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    scanf("%d%d%d",&n,&m,&k);
    M=min(N-5,min(n,m));Smu[1]=mu[1]=1;
    fp(i,2,M){
        if(!is[i])pr[++pr[0]]=i,mu[i]=-1;
        for(int j=1,x;j<=pr[0]&&(x=i*pr[j])<=M;++j){
            is[x]=1;if(i%pr[j])mu[x]=-mu[i];else break;
        }Smu[i]=Smu[i-1]+mu[i];
    }
    fp(i,1,k)f[i]=f[i-1]+(gcd(i,k)==1);
    fp(i,2,k){
        for(int j=2;;++j)if(i%j==0&&!is[j]){p[i]=j;break;}
        for(q[i]=i;q[i]%p[i]==0;)q[i]/=p[i];
    }
    int i=1,j=sqrt(min(n,m)),x,y,s,t=0;long long w=0;
    for(;i<=j;++i,t=s)s=g(i,k),w+=1ll*(n/i)*Sf(m/i)*(s-t);
    for(;i<=min(n,m);i=j+1,t=s)x=n/i,y=m/i,j=min(n/x,m/y),
        s=g(j,k),w+=1ll*x*Sf(y)*(s-t);
    printf("%lld",w);
return 0;
}

二:考虑处理 [(j,k)=1] [ ( j , k ) = 1 ]

f(n,m,k)=ni=1mj=1[(i,j)=1][(j,k)=1] f ( n , m , k ) = ∑ i = 1 n ∑ j = 1 m [ ( i , j ) = 1 ] [ ( j , k ) = 1 ]

=ni=1mj=1[(i,j)=1]d|(j,k)μ(d) = ∑ i = 1 n ∑ j = 1 m [ ( i , j ) = 1 ] ∑ d | ( j , k ) μ ( d )

=ni=1mjd=1[(i,jd)=1]d|jd,d|kμ(d) = ∑ i = 1 n ∑ j d = 1 m [ ( i , j d ) = 1 ] ∑ d | j d , d | k μ ( d )

=d|kμ(d)ni=1mdj=1[(i,jd)=1] = ∑ d | k μ ( d ) ∑ i = 1 n ∑ j = 1 m d [ ( i , j d ) = 1 ]

=d|kμ(d)ni=1mdj=1[(i,j)=1][(i,d)=1] = ∑ d | k μ ( d ) ∑ i = 1 n ∑ j = 1 m d [ ( i , j ) = 1 ] [ ( i , d ) = 1 ]

=d|kμ(d)f(md,n,d) = ∑ d | k μ ( d ) f ( m d , n , d )

边界 f(0,m,k)=f(n,0,k)=0 f ( 0 , m , k ) = f ( n , 0 , k ) = 0

然后 k=1 k = 1 就是简单处理一下 ni=1mj=1[(i,j)=1]=nd=1μ(d)ndmd ∑ i = 1 n ∑ j = 1 m [ ( i , j ) = 1 ] = ∑ d = 1 n μ ( d ) n d m d ok o k

复杂度是 O(lognlogmn+n23) O ( log ⁡ n log ⁡ m n + n 2 3 )

#include<map>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define fp(i,a,b) for(int i=a,I=b;i<=I;++i)
#define fd(i,a,b) for(int i=a,I=b;i>=I;--i)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
const int N=1e7+5;
typedef int arr[N];
typedef long long ll;
struct da{int n,m,k;inline bool operator<(const da&b)const{return n==b.n?(m==b.m?k<b.k:m<b.m):n<b.n;}};
int n,m,k,M,K[2000];arr is,pr,mu,Smu;map<int,int>Am;map<da,ll>Ans;
int Sm(int x){
    if(x<=M)return Smu[x];
    if(Am[x])return Am[x];
    int w=1,i=2,j=sqrt(x);
    for(;i<=j;++i)w-=Sm(x/i);
    for(;i<=x;i=j+1)j=x/(x/i),w-=(j-i+1)*Sm(x/i);
    return Am[x]=w;
}
ll sol(int n,int m,int k){
    if(!n||!m)return 0;
    da now=da{n,m,k};
    if(Ans[now])return Ans[now];ll w=0;
    if(k==1){
        if(n>m)swap(n,m);
        int i=1,j=sqrt(n),s,t=0,x,y;
        for(;i<=j;++i,t=s)s=Sm(i),w+=1ll*(n/i)*(m/i)*(s-t);
        for(;i<=n;i=j+1,t=s)x=n/i,y=m/i,j=min(n/x,m/y),s=Sm(j),w+=1ll*x*y*(s-t);
        Ans[da{m,n,k}]=w;
    }else for(int i=1;i<=K[0]&&K[i]<=k;++i)
            if(k%K[i]==0&&mu[K[i]])
                w+=sol(m/K[i],n,K[i])*mu[K[i]];
    return Ans[now]=w;
}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    scanf("%d%d%d",&n,&m,&k);
    M=min((int)1e7,max(k,min(n,m)));mu[1]=1;
    fp(i,2,M){
        if(!is[i])pr[++pr[0]]=i,mu[i]=-1;
        for(int j=1,x;j<=pr[0]&&(x=i*pr[j])<=M;++j){
            is[x]=1;
            if(i%pr[j])mu[x]=-mu[i];
            else{mu[x]=0;break;}
        }
    }fp(i,1,M)Smu[i]=Smu[i-1]+mu[i];
    fp(i,1,k)if(k%i==0)K[++K[0]]=i;
    printf("%lld",sol(n,m,k));
return 0;
}

如果是考场我还是会选择法二的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值