$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 }
前面有个$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$前缀和处理出来。