【BZOJ 4652】【NOI 2016】循环之美

时间:2023-03-09 03:53:06
【BZOJ 4652】【NOI 2016】循环之美

题目连接:

  传送

题解:

  真是一道好题……

一:

  一个分数$\frac{x}{y}$完全循环当其第一次出现时,当且仅当y与k互质,x与y互质,且y不等于1。

  整数情况下y一定为1,即也满足以上判断。

  推导:

    方法一:打表找规律= =

    方法二:x与y互质去重= =,设循环次数为l,则对于循环节第一次循环前剩余$x\mod y$,第二次循环前剩余$xk^l\mod y$,若其为循环则满足:【BZOJ 4652】【NOI 2016】循环之美,由x与y互质可知存在x对y的逆元,所以:

        【BZOJ 4652】【NOI 2016】循环之美

由贝祖定理可知,k与y互质。

二、反演:

          【BZOJ 4652】【NOI 2016】循环之美

  考虑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);
}