【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 }

 

 

 

 

没有什么不可能。
posted @ 2018-01-22 07:45  Troywar  阅读(267)  评论(0编辑  收藏  举报