挖了很久的坑qaq
还记得第一次xtx神犇给我们讲这道题,已经过去快整整一年了呢owo
首先怎么算是纯循环小数呢?
因为要求数值不同的数对个数,因此我们只考虑gcd(x,y)==1的数对(x,y)。
什么时候会出现循环呢?当出现相同余数时。那纯循环呢?就要求第一次出现的相同余数为x%y。即只需要满足
xkl≡xmody,l>0
x
k
l
≡
x
mod
y
,
l
>
0
,其中l就是循环节长度。
又因为(x,y)=1,所以
(k,y)=1
(
k
,
y
)
=
1
。
因此我们就是要求
∑x=1n∑y=1m[gcd(x,y)==1,gcd(y,k)==1]
∑
x
=
1
n
∑
y
=
1
m
[
gcd
(
x
,
y
)
==
1
,
gcd
(
y
,
k
)
==
1
]
∑y=1m[gcd(y,k)==1]∑x=1n[gcd(x,y)==1]
∑
y
=
1
m
[
gcd
(
y
,
k
)
==
1
]
∑
x
=
1
n
[
gcd
(
x
,
y
)
==
1
]
把后一部分Mobius反演一下就是
∑y=1m[gcd(y,k)==1]∑d|ynμ(d)⌊nd⌋
∑
y
=
1
m
[
gcd
(
y
,
k
)
==
1
]
∑
d
|
y
n
μ
(
d
)
⌊
n
d
⌋
改变枚举顺序可以得到:
∑d=1nμ(d)⌊nd⌋∑y=1⌊md⌋[gcd(yd,k)==1]
∑
d
=
1
n
μ
(
d
)
⌊
n
d
⌋
∑
y
=
1
⌊
m
d
⌋
[
g
c
d
(
y
d
,
k
)
==
1
]
∑d=1n[gcd(d,k)==1]μ(d)⌊nd⌋∑y=1⌊md⌋[gcd(y,k)==1]
∑
d
=
1
n
[
gcd
(
d
,
k
)
==
1
]
μ
(
d
)
⌊
n
d
⌋
∑
y
=
1
⌊
m
d
⌋
[
gcd
(
y
,
k
)
==
1
]
记
f(n,k)=∑i=1n[gcd(i,k)==1]
f
(
n
,
k
)
=
∑
i
=
1
n
[
g
c
d
(
i
,
k
)
==
1
]
我们显然有
f(n,k)=⌊nk⌋f(k,k)+f(n%k,k)
f
(
n
,
k
)
=
⌊
n
k
⌋
f
(
k
,
k
)
+
f
(
n
%
k
,
k
)
因此我们可以预处理出
O(K)
O
(
K
)
级别的f的前缀和,这样就可以
O(1)
O
(
1
)
计算后一部分了,这样总体复杂度就是
O(n)
O
(
n
)
,可以获得84分。
考虑进一步的优化,记 g(n,k)=∑i=1n[gcd(i,k)==1]μ(i) g ( n , k ) = ∑ i = 1 n [ g c d ( i , k ) == 1 ] μ ( i ) 如果我们可以处理出这个东西得前缀和我们就可以分块算了。
我们先考虑
k
k
的一个质因数,那么
k
k
显然可以写成的形式。由于在[1,n]的范围中只有与
k
k
互质的才是有效值,那么若(x,k)==1,我们可以得到(x,p)==1且(x,q)==1。于是,我们可以考虑从(x,q)==1的取值中减去x不与p互质的部分,就可以得到(x,k)==1的部分。
剩下的部分去看大神blog吧,懒得搬了qaq
portal
最后g这个函数是可以递归计算的。复杂度
边界为k=1时函数值就是mu的前缀和,可以杜教筛来搞,n<=1时为n。
总的复杂度大概是
O(n−−√w(k)+n2/3)
O
(
n
w
(
k
)
+
n
2
/
3
)
要写hash表qaq然而我还是跑不过luogu,人称被卡常数。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 1000010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int prime[N>>3],tot=0,a[10],cnt=0,K,h[N],num=0,h1[5][N],num1=0;
ll mu[N],f[2010],ans=0;
bool notprime[N];
struct Hash_Table{
int key,val,next;
}data[N],data1[N<<3];
inline int hs(int key){
int x=key%N;
for(int i=h[x];i;i=data[i].next)
if(data[i].key==key) return data[i].val;
return -1;
}
inline int ins(int key,int val){
int x=key%N;
data[++num].next=h[x];h[x]=num;data[num].key=key;data[num].val=val;
}
inline int gcd(int x,int y){return y?gcd(y,x%y):x;}
inline void init(){
notprime[1]=1;mu[1]=1;
for(int i=2;i<=1e6;++i){
if(!notprime[i]) prime[++tot]=i,mu[i]=-1;
for(int j=1;prime[j]*i<=1e6;++j){
notprime[prime[j]*i]=1;
if(i%prime[j]==0){
mu[i*prime[j]]=0;break;
}mu[i*prime[j]]=-mu[i];
}
}for(int i=2;i<=1e6;++i) mu[i]+=mu[i-1];
for(int i=1;i<=K;++i) if(gcd(K,i)==1) f[i]=1;
for(int i=1;i<=K;++i) f[i]+=f[i-1];
for(int i=1;prime[i]<=K;++i) if(K%prime[i]==0) a[++cnt]=prime[i];
}
inline ll calm(int n){return (n/K)*f[K]+f[n%K];}
inline ll calmu(int n){
if(n<=1e6) return mu[n];
int res=hs(n);if(res>0) return res;res=1;
for(int i=2,lst;i<=n;i=lst+1){
lst=n/(n/i);res-=calmu(n/i)*(lst-i+1);
}ins(n,res);return res;
}
inline ll g(int n,int k){
if(!k) return calmu(n);
if(n<=1) return n;int x=n%N;
for(int i=h1[k][x];i;i=data1[i].next)
if(data1[i].key==n) return data1[i].val;
ll res=g(n,k-1)+g(n/a[k],k);
data1[++num1].next=h1[k][x];h1[k][x]=num1;data1[num1].key=n;
data1[num1].val=res;return res;
}
int main(){
// freopen("a.in","r",stdin);
int n=read(),m=read();K=read();init();
for(int i=1,lst;i<=min(n,m);i=lst+1){
lst=min(n/(n/i),m/(m/i));
ans+=(g(lst,cnt)-g(i-1,cnt))*(n/i)*calm(m/i);
}printf("%lld\n",ans);
return 0;
}
7.3upd:重打了一遍就跑过去了???还贼快???
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 1000003
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int K,mu[N],prime[N>>3],tot=0,f[2010],h1[5][N],num1=0,cnt=0,a[5],num=0,h[N];
bool notprime[N];
struct Hash_table{
int key,val,next;
}data1[N],data[N];
inline int gcd(int x,int y){return y?gcd(y,x%y):x;}
inline void init(){
notprime[1]=1;mu[1]=1;
for(int i=2;i<=N-3;++i){
if(!notprime[i]) prime[++tot]=i,mu[i]=-1;
for(int j=1;prime[j]*i<=N-3;++j){
notprime[prime[j]*i]=1;
if(i%prime[j]==0){
mu[i*prime[j]]=0;break;
}mu[i*prime[j]]=-mu[i];
}
}for(int i=1;i<=N-3;++i) mu[i]+=mu[i-1];
for(int i=1;i<=K;++i) f[i]=gcd(i,K)==1;
for(int i=1;i<=K;++i) f[i]+=f[i-1];
for(int i=1;prime[i]<=K;++i) if(K%prime[i]==0) a[++cnt]=prime[i];
}
inline ll F(int x){return x/K*f[K]+f[x%K];}
inline int calmu(int n){
if(n<=1e6) return mu[n];
int x=n%N;
for(int i=h[x];i;i=data[i].next)
if(data[i].key==n) return data[i].val;
int res=1;
for(int i=2,lst;i<=n;i=lst+1){
lst=n/(n/i);res-=calmu(n/i)*(lst-i+1);
}data[++num].next=h[x];h[x]=num;data[num].key=n;data[num].val=res;
return res;
}
inline ll g(int n,int k){
if(!k) return calmu(n);if(n<=1) return n;
int x=n%N;
for(int i=h1[k][x];i;i=data1[i].next)
if(data1[i].key==n) return data1[i].val;
int res=g(n,k-1)+g(n/a[k],k);
data1[++num1].next=h1[k][x];h1[k][x]=num1;data1[num1].key=n;
data1[num1].val=res;return res;
}
int main(){
// freopen("a.in","r",stdin);
int n=read(),m=read();K=read();init();ll ans=0;
for(int i=1,lst;i<=min(n,m);i=lst+1){
lst=min(n/(n/i),m/(m/i));
ans+=(g(lst,cnt)-g(i-1,cnt))*(n/i)*F(m/i);
}printf("%lld\n",ans);
return 0;
}