zoukankan      html  css  js  c++  java
  • *LOJ#2085. 「NOI2016」循环之美

    $n leq 1e9,m leq 1e9,k leq 2000$,求$k$进制下$frac{x}{y}$有多少种不同的纯循环数取值,$1 leq x leq n,1 leq y leq m$。纯循环数是指小数点后直接就开始循环,整数也算。

    与上个题的丑陋相比这个题不知道美到哪里去。。虽然自己没想出来。

    提示说了,出现相同余数时有纯循环。假设循环节是$l$,那么$xk^l$和$x$除$y$会得到相同余数--同余!$xk^l equiv x (mod y)$。由于题目要互不相同的,所以$x$和$y$互质,有逆元。两边同乘$x$的逆元,得$k^l equiv 1 (mod y)$,存在这样的$l$,由欧拉定理得只需$k$与$y$互质即可。可以开始推式子。

    $\ sum_{x=1}^{n}sum_{y=1}^m[(x,y)=1][(k,y)=1]$
    $\ =sum_{y=1}^{m}[(k,y)=1]sum_{x=1}^{n}[(x,y)=1]$
    $\ =sum_{y=1}^{m}[(k,y)=1]sum_{x=1}^{n}sum_{d|x,d|y}mu(d)$
    $\ =sum_{y=1}^{m}[(k,y)=1]sum_{d|y}mu(d)left lfloor frac{n}{d} ight floor$
    $\ =sum_{d=1}^{m}mu(d)left lfloor frac{n}{d} ight floorsum_{d|y,y leq m}[(k,y)=1]$
    $\ =sum_{d=1}^{m}mu(d)left lfloor frac{n}{d} ight floorsum_{i=1}^{left lfloor frac{m}{d} ight floor}[(k,i)=1][(k,d)=1]$
    $\ =sum_{d=1}^{min(n,m)}mu(d)left lfloor frac{n}{d} ight floor[(k,d)=1]sum_{i=1}^{left lfloor frac{m}{d} ight floor}[(k,i)=1]$

    可以发现$f(t)=sum_{i=1}^t[(k,i)=1]=left lfloor frac{t}{k} ight floor f(k)+f(t mod k)$。这样就可以O(1)算后面那坨,在min(n,m)的时间内得到84分。

     1 //#include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 //#include<math.h>
     5 //#include<set>
     6 //#include<queue>
     7 //#include<bitset>
     8 //#include<vector>
     9 #include<algorithm>
    10 #include<stdlib.h>
    11 using namespace std;
    12 
    13 #define LL long long
    14 int qread()
    15 {
    16     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
    17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
    18 }
    19 
    20 //Pay attention to '-' , LL and double of qread!!!!
    21 
    22 int n,m,K;
    23 int f[2011];
    24 
    25 #define maxm 20000011
    26 int miu[maxm],prime[maxm],lp=0; bool notprime[maxm];
    27 void pre(int n)
    28 {
    29     miu[1]=1;
    30     for (int i=2;i<=n;i++)
    31     {
    32         if (!notprime[i]) {prime[++lp]=i; miu[i]=-1;}
    33         for (int tmp,j=1;j<=lp && 1ll*i*prime[j]<=n;j++)
    34         {
    35             notprime[tmp=i*prime[j]]=1;
    36             if (i%prime[j]) miu[tmp]=-miu[i];
    37             else {miu[tmp]=0; break;}
    38         }
    39     }
    40 }
    41 
    42 int gcd(int a,int b) {while (b^=a^=b^=a%=b); return a;}
    43 int getf(int x) {return x/K*f[K]+f[x%K];}
    44 
    45 int main()
    46 {
    47     n=qread(); m=qread(); K=qread();
    48     for (int i=1;i<=K;i++) f[i]=f[i-1]+(gcd(i,K)==1);
    49     pre(min(n,m));
    50     LL ans=0;
    51     for (int i=1,to=min(n,m);i<=to;i++) if ((i%K>0) && (f[i%K]-f[(i-1)%K])>0)
    52         ans+=miu[i]*(n/i)*1ll*getf(m/i);
    53     printf("%lld
    ",ans);
    54     return 0;
    55 }
    View Code

    前面有个$left lfloor frac{n}{d} ight floor$是可以分块枚举的,如果能求快一点对所有$t=left lfloor frac{n}{d} ight floor$求出$g(t,k)=sum_{i=1}^t[(i,k)=1]mu(i)$就好了。

    !$k=p^cq$,设$p$为$k$的一个质因子,则$k$可以这么表示,其中$(q,p)=1$。要求与$k$互质的,那就求与$q$互质的,挑掉与$p$不互质和与$q$互质的。与$p$不互质的有一定是$p$的倍数,因为$p$是质数嘛。所以

    $\ g(t,k)=sum_{i=1}^{t}[(k,i)=1]mu(i)$
    $\ =sum_{i=1}^{t}[(i,q)=1]mu(i)-sum_{j=1}^{left lfloor frac{t}{p} ight floor}[(jp,q)=1]mu(jp)$
    $\ =g(t,q)-mu(p)g(left lfloor frac{t}{p} ight floor,q)$
    $\ =g(t,q)+g(left lfloor frac{t}{p} ight floor,q)$

    建立一个根号复杂度的递推关系,$k$那一维的数量是常数级别的,毕竟2000以内质因子最多的数也没几个质因子。递归边界的话,如果t=0直接返回0,如果k=1那就是$mu$的前缀和,需要再写一个杜教筛对所有n除以d的下取整数值的$mu$前缀和处理出来。

  • 相关阅读:
    ASP.NET 篇
    .NET Core 篇
    JS-CSS篇
    IIS使用篇
    WebService篇
    电脑使用篇
    数据库使用篇
    正则表达式篇
    Linux学习篇
    Leetcode 198. 打家劫舍 dp
  • 原文地址:https://www.cnblogs.com/Blue233333/p/9253286.html
Copyright © 2011-2022 走看看