【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$,若其为循环则满足:,由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)$
代码:
1 #include "bits/stdc++.h" 2 3 using namespace std; 4 5 const int N=2e7+5; 6 7 int prim[N],num,miu[N],pre[N]; 8 bool vis[N]; 9 10 inline void init(){ 11 miu[1]=1; 12 pre[1]=1; 13 register int i,j; 14 for( i=2;i<N;++i){ 15 if(!vis[i]) 16 prim[++num]=i,miu[i]=-1; 17 for( j=1;prim[j]*i<N;++j){ 18 vis[i*prim[j]]=true; 19 if(i%prim[j]) { 20 miu[i*prim[j]]=-miu[i]; 21 }else{ 22 miu[i*prim[j]]=0;break; 23 } 24 } 25 pre[i]+=pre[i-1]+miu[i]; 26 } 27 } 28 29 int n,m,k,wr[N],cnt; 30 int fac[2005][10005]; 31 vector<int> factor[2005]; 32 33 map<int,int> ss; 34 35 inline int Get_miu(int x){ 36 if(x<N) return pre[x]; 37 if(ss.count(x)) return ss[x]; 38 int ans=1; 39 for(int i=2,pos;i<=x;i=pos+1){ 40 pos=x/(x/i); 41 ans-=Get_miu(x/i)*(pos-i+1); 42 } 43 return ss[x]=ans; 44 } 45 46 inline int get_miu(int x,int sg){ 47 if(sg==1)return Get_miu(x); 48 if(x<=10000) return fac[sg][x]; 49 else { 50 int p=wr[sg]; 51 return get_miu(x/p,sg)-get_miu(x,sg/p); 52 } 53 } 54 55 int main(){ 56 // freopen("1.out","r",stdin); 57 // freopen("b1.out","w",stdout); 58 scanf("%d%d%d",&n,&m,&k); 59 init(); 60 for(int i=1;i<=k;++i) 61 for(int j=1;j<=i;++j) 62 if(i%j==0) factor[i].push_back(j); 63 64 for(int i=1;i<=2000;++i) 65 for(int j=1;prim[j]<=i;++j) if(i%prim[j]==0) wr[i]=prim[j]; 66 for(int i=1;i<=2000;++i) 67 if(k%i==0) 68 for(int j=1;j<=10000;++j) 69 fac[i][j]=fac[i][j-1]+miu[j*i]; 70 71 long long ans=0,sum; 72 register int d,pos; 73 int last,now,nn,mm,t1,t2,t,g,s,p,q; 74 for(int i=0;i<factor[k].size();++i){ 75 t=factor[k][i]; 76 sum=0; 77 for( p=0;p<factor[t].size();++p){ 78 g=factor[t][p]; 79 for( q=0,s;q<factor[t/g].size();++q){ 80 s=factor[t/g][q]; 81 t1=s*g,t2=s*t; 82 nn=n/t1,mm=m/t2; 83 last=0,now; 84 if(miu[s*g]==0) continue; 85 for(d=1,pos;d<=min(nn,mm);d=pos+1){ 86 pos=min(nn/(nn/d),mm/(mm/d)); 87 now=get_miu(pos,s*g); 88 sum+=(now-last)*1ll*(nn/d)*(mm/d)*miu[s]; 89 last=now; 90 } 91 } 92 } 93 ans+=sum*miu[t]; 94 } 95 printf("%lld\n",ans); 96 }
没有什么不可能。