
题目连接:
题解:
真是一道好题……
一:
一个分数$\frac{x}{y}$完全循环当其第一次出现时,当且仅当y与k互质,x与y互质,且y不等于1。
整数情况下y一定为1,即也满足以上判断。
推导:
方法一:打表找规律= =
方法二:x与y互质去重= =,设循环次数为l,则对于循环节第一次循环前剩余$x\mod y$,第二次循环前剩余$xk^l\mod y$,若其为循环则满足:,由x与y互质可知存在x对y的逆元,所以:
由贝祖定理可知,k与y互质。
二、反演:
考虑d前面时间复杂度为$O(\sqrt{k}\ln k)$,后边分块时间复杂度$O(\sqrt n)$
考虑如何得到$S(n,sg)=\sum_{i=1}^n \mu(isg)$。
1.当$\mu(sg)==0$时,上式为0;
2.设p为sg质因数,则有$S(n,sg)=\sum_{i=1}^n\mu(i)([p|i]-1)$,故$S(n,sg)=S(n/p,sg)-S(n,sg/p)$。
故求一次$S(n,sg)$的时间复杂度约为$(O(2^{k的质因子个数}))$。
三、时间复杂度
$O(\sqrt{nk}\ln k)$
代码:
#include "bits/stdc++.h" using namespace std; const int N=2e7+; int prim[N],num,miu[N],pre[N];
bool vis[N]; inline void init(){
miu[]=;
pre[]=;
register int i,j;
for( i=;i<N;++i){
if(!vis[i])
prim[++num]=i,miu[i]=-;
for( j=;prim[j]*i<N;++j){
vis[i*prim[j]]=true;
if(i%prim[j]) {
miu[i*prim[j]]=-miu[i];
}else{
miu[i*prim[j]]=;break;
}
}
pre[i]+=pre[i-]+miu[i];
}
} int n,m,k,wr[N],cnt;
int fac[][];
vector<int> factor[]; map<int,int> ss; inline int Get_miu(int x){
if(x<N) return pre[x];
if(ss.count(x)) return ss[x];
int ans=;
for(int i=,pos;i<=x;i=pos+){
pos=x/(x/i);
ans-=Get_miu(x/i)*(pos-i+);
}
return ss[x]=ans;
} inline int get_miu(int x,int sg){
if(sg==)return Get_miu(x);
if(x<=) return fac[sg][x];
else {
int p=wr[sg];
return get_miu(x/p,sg)-get_miu(x,sg/p);
}
} int main(){
// freopen("1.out","r",stdin);
// freopen("b1.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
init();
for(int i=;i<=k;++i)
for(int j=;j<=i;++j)
if(i%j==) factor[i].push_back(j); for(int i=;i<=;++i)
for(int j=;prim[j]<=i;++j) if(i%prim[j]==) wr[i]=prim[j];
for(int i=;i<=;++i)
if(k%i==)
for(int j=;j<=;++j)
fac[i][j]=fac[i][j-]+miu[j*i]; long long ans=,sum;
register int d,pos;
int last,now,nn,mm,t1,t2,t,g,s,p,q;
for(int i=;i<factor[k].size();++i){
t=factor[k][i];
sum=;
for( p=;p<factor[t].size();++p){
g=factor[t][p];
for( q=,s;q<factor[t/g].size();++q){
s=factor[t/g][q];
t1=s*g,t2=s*t;
nn=n/t1,mm=m/t2;
last=,now;
if(miu[s*g]==) continue;
for(d=,pos;d<=min(nn,mm);d=pos+){
pos=min(nn/(nn/d),mm/(mm/d));
now=get_miu(pos,s*g);
sum+=(now-last)*1ll*(nn/d)*(mm/d)*miu[s];
last=now;
}
}
}
ans+=sum*miu[t];
}
printf("%lld\n",ans);
}