【luogu P6860】象棋与马(数学)(杜教筛)

象棋与马

题目链接:luogu P6860

题目大意

给你一个数 n,然后问你有多少个 a<=n,b<=n 满足在一个二维网格上从源点出发每次走一个 a*b 的矩阵,能走到图上的所有整点。

思路

首先考虑怎样的点对是满足条件的。

首先我们考虑如果它能从 ( 0 , 0 ) (0,0) (0,0) 走到 ( 0 , 1 ) (0,1) (0,1),那它就能走到所有点。(因为你可以一步一步走)

那接着考虑怎么搞,首先顺序无关,所以我们可以把它分成两段位移: ( ± x , ± y ) (\pm x,\pm y) (±x,±y) ( ± y , ± x ) (\pm y,\pm x) (±y,±x)

然后第一段的整体位移可以表示成 ( 2 a x , 2 b y ) (2ax,2by) (2ax,2by) 或者 ( 2 a x + x , 2 b y + y ) (2ax+x,2by+y) (2ax+x,2by+y),第二段就是 ( 2 c y , 2 d x ) (2cy,2dx) (2cy,2dx) ( 2 c y + y , 2 d x + x ) (2cy+y,2dx+x) (2cy+y,2dx+x)

考虑列出四种可能的方法:
{ 2 a x = 2 c y 2 b y = 2 d x + 1 \left\{\begin{matrix} 2ax=2cy \\ 2by=2dx+1 \end{matrix}\right. { 2ax=2cy2by=2dx+1

{ 2 a x + x = 2 c y 2 b y + y = 2 d x + 1 \left\{\begin{matrix} 2ax+x=2cy \\ 2by+y=2dx+1 \end{matrix}\right. { 2ax+x=2cy2by+y=2dx+1

{ 2 a x = 2 c y + y 2 b y = 2 d x + x + 1 \left\{\begin{matrix} 2ax=2cy+y \\ 2by=2dx+x+1 \end{matrix}\right. { 2ax=2cy+y2by=2dx+x+1

{ 2 a x + x = 2 c y + y 2 b y + y = 2 d x + x + 1 \left\{\begin{matrix} 2ax+x=2cy+y \\ 2by+y=2dx+x+1 \end{matrix}\right. { 2ax+x=2cy+y2by+y=2dx+x+1

然后解四个方程,第一是 2 ( a x − c y ) = 0 , 2 ( b y − d x ) = 1 2(ax-cy)=0,2(by-dx)=1 2(axcy)=0,2(bydx)=1,由于 x , y x,y x,y 互质,所以 b y − d x by-dx bydx 会可以是任意整数(设为 k k k 下同):
2 k = 0 , 2 k = 1 2k=0,2k=1 2k=0,2k=1,无解

第二个是跟上面差不多,就是 2 k + x = 0 , 2 k + y = 1 2k+x=0,2k+y=1 2k+x=0,2k+y=1,那就是 x x x 是偶数, y y y 是奇数。

第三个就是 2 k − y = 0 , 2 k − x = 1 2k-y=0,2k-x=1 2ky=0,2kx=1,那就是 y y y 是偶数, x x x 是奇数。

第四个是 2 k + x − y = 0 , 2 k + y − x = 1 2k+x-y=0,2k+y-x=1 2k+xy=0,2k+yx=1,那就是无解。

那综上,我们可以总结出合法的情况:
gcd ⁡ ( i , j ) = 1 \gcd(i,j)=1 gcd(i,j)=1,且 i + j i+j i+j 是奇数。


然后考虑如何继续求,那 i + j i+j i+j 是奇数, i − j i-j ij 自然也是。
然后根据辗转相减法: gcd ⁡ ( i , j ) = 1 \gcd(i,j)=1 gcd(i,j)=1 就有 gcd ⁡ ( i , i − j ) = 1 \gcd(i,i-j)=1 gcd(i,ij)=1
你考虑设 i > j i>j i>j(到时算出来答案乘 2 2 2,因为显然 i = j i=j i=j 是不成立)

∑ i = 1 n ∑ j = 1 i − 1 2 [ ( g c d ( i , j ) = 1 ) & ( ( i − j )   m o d   2 = 1 ) ] \sum\limits_{i=1}^n\sum\limits_{j=1}^{i-1}2[(gcd(i,j)=1)\&((i-j)\bmod 2=1)] i=1nj=1i12[(gcd(i,j)=1)&((ij)mod2=1)]

然后发现如果不看奇偶它就是 ∑ i = 1 n φ ( i ) \sum\limits_{i=1}^n\varphi(i) i=1nφ(i),那你考虑有了右边之后会怎么样。
考虑这个新的值是 w ( i ) w(i) w(i)
(原来的式子变成: ∑ i = 1 n 2 w ( i ) \sum\limits_{i=1}^n2w(i) i=1n2w(i)

考虑从 φ ( i ) \varphi(i) φ(i) 的性质考虑,如果 i i i 是偶数,那所有偶数跟它都不是互质的,那这个操作就不会影响,所以 w ( i ) = φ ( i ) w(i)=\varphi(i) w(i)=φ(i)
如果 i i i 是奇数,那我们考虑一个东西,就是这个互质的对称性。
什么意思呢,就是如果 i , j i,j i,j 互质( i > j i>j i>j),那么 i , i − j i,i-j i,ij 也互质。

那我们就其实可以看做是 w ( i ) = φ ( i ) 2 w(i)=\dfrac{\varphi(i)}{2} w(i)=2φ(i),当然你会发现 w ( 1 ) w(1) w(1) 要特判掉。(应该是 0 0 0 而不是 1 2 \dfrac{1}{2} 21
(其实可以不特判,然后到时答案减 1 1 1 即可,减一是因为后面乘 2 2 2

然后你就可以列出 w ( i ) = { φ ( i ) i m o d    2 = 0 φ ( i ) 2 i m o d    2 = 1 w(i)=\left\{\begin{matrix}\varphi(i)&i\mod2=0 \\ \dfrac{\varphi(i)}{2}&i\mod2=1\end{matrix}\right. w(i)={ φ(i)2φ(i)imod2=0imod2=1

然后把 2 2 2 放进去:
2 w ( i ) = { 2 φ ( i ) i m o d    2 = 0 φ ( i ) i m o d    2 = 1 2w(i)=\left\{\begin{matrix}2\varphi(i)&i\mod2=0 \\ \varphi(i)&i\mod2=1\end{matrix}\right. 2w(i)={ 2φ(i)φ(i)imod2=0imod2=1
2 w ( i ) = φ ( i ) + { φ ( i ) i m o d    2 = 0 0 i m o d    2 = 1 2w(i)=\varphi(i)+\left\{\begin{matrix}\varphi(i)&i\mod2=0 \\ 0&i\mod2=1\end{matrix}\right. 2w(i)=φ(i)+{ φ(i)0imod2=0imod2=1

然后放回原来的式子:
∑ i = 1 n 2 w ( i ) \sum\limits_{i=1}^n2w(i) i=1n2w(i)
∑ i = 1 n φ ( i ) + ∑ i = 1 n { φ ( i ) i m o d    2 = 0 0 i m o d    2 = 1 \sum\limits_{i=1}^n\varphi(i)+\sum\limits_{i=1}^n\left\{\begin{matrix}\varphi(i)&i\mod2=0 \\ 0&i\mod2=1\end{matrix}\right. i=1nφ(i)+i=1n{ φ(i)0imod2=0imod2=1

那我们再看右边的部分,那只看有值的,就是偶数的。
然后再从递推式求的方式来看 i 2 \dfrac{i}{2} 2i,如果它是偶数那返回的就是 φ ( i 2 ) \varphi(\dfrac{i}{2}) φ(2i),否则就是 φ ( i 2 ) 2 \dfrac{\varphi(\frac{i}{2})}{2} 2φ(2i),你会发现它就是 w ( ⌊ i 2 ⌋ ) w(\left\lfloor\dfrac{i}{2}\right\rfloor) w(2i) 的值。

然后就有:
∑ i = 1 n w ( i ) = ∑ i = 1 n φ ( i ) + ∑ i = 1 ⌊ i 2 ⌋ w ( i ) \sum\limits_{i=1}^nw(i)=\sum\limits_{i=1}^n\varphi(i)+\sum\limits_{i=1}^{\left\lfloor\frac{i}{2}\right\rfloor}w(i) i=1nw(i)=i=1nφ(i)+i=12iw(i)
左边的用杜教筛,右边的递归下去就好了。

复杂度是 O ( n 2 3 log ⁡ n ) O(n^{\frac{2}{3}}\log n) O(n32logn),看似很危,但其实跑不满(每次递归的 n n n 越来越小)可以过。

代码

#include<map>
#include<cstdio>
#define ll unsigned long long

using namespace std;

//const ll Maxn = 21544346.900318837217592935665195;
const ll Maxn = 22000000;
int T;
ll n, ans, phi[Maxn + 1], prime[Maxn / 10];
bool np[Maxn + 1];
map <int, ll> ans_phi;

void init() {
    
    //phi 的预处理
	phi[1] = 1;
	for (int i = 2; i <= Maxn; i++) {
    
    
		if (!np[i]) {
    
    
			phi[i] = i - 1; prime[++prime[0]] = i;
		}
		for (int j = 1; j <= prime[0] && i * prime[j] <= Maxn; j++) {
    
    
			if (i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j] - 1), np[i * prime[j]] = 1;
				else {
    
    
					phi[i * prime[j]] = phi[i] * prime[j], np[i * prime[j]] = 1;
					break;
				}
		}
	}
	for (int i = 1; i <= Maxn; i++) phi[i] += phi[i - 1];
} 

ll get_phi(ll n) {
    
    //杜教筛
	if (n < Maxn) return phi[n];
	if (ans_phi[n]) return ans_phi[n];
	ll re = (n & 1llu) ? (1llu + n) / 2llu * n : n / 2llu * (1llu + n);
	for (ll l = 2, r; l <= n; l = r + 1) {
    
    
		r = n / (n / l);
		re -= (r - l + 1) * get_phi(n / l);
	}
	return ans_phi[n] = re;
}

ll F(ll n) {
    
    
	if (!n) return 0;
	return get_phi(n) + F(n / 2);
}

int main() {
    
    
	init();
	
	scanf("%d", &T);
	while (T--) {
    
    
		scanf("%llu", &n);
		printf("%llu\n", F(n) - 1llu);
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/121107969