【洛谷P6860】象棋与马

题目

题目链接:https://www.luogu.com.cn/problem/P6860
Amazing John 有一个无限大的棋盘来下马棋。

有一个马最开始在 ((0,0)),它的每一步可以走一个 (a imes b) 的矩形( 即能够从((x,y))到达 ((xpm a,ypm b))((xpm b,ypm a)) )。

若马通过上述移动方式可以到达棋盘中任意一个点,那么 (p(a,b)=1),否则 (p(a,b)=0)

现在 Amazing John 给你 (T) 组询问,每组询问他会给出一个正整数 (n),他想知道

[left ( sum_{a=1}^nsum_{b=1}^np(a,b) ight )mod 2^{64} ]

的值。

思路

[mathrm{Qcolor{red}{uantAsk} YYDS!} ]

显然马可以走到任意点的充要条件就是可以走到 ((1,0))。我们可以列出马可以走到的点的集合,容易得出它可以走到 ((1,0)) 的充要条件是 (gcd(a,b)=1)(a+b) 是奇数。这个条件等价于 (gcd(a,b)=1)(a-b) 是奇数。
如果 (a) 是偶数,那么显然任意小于 (a) 且与 (a) 互质的数都满足 (a-b) 是奇数,所以此时合法的 (b) 的数量就是 (varphi(a))
如果 (a) 是奇数,如果 (gcd(a,b)=1),那么 (gcd(a-b)) 显然也是 (1),而 (b)(a-b) 中恰好是一奇一偶,所以任意一个与 (a) 互质的奇数都对应一个与 (a) 互质的偶数,所以此时合法的 (b) 的数量是 (frac{varphi(a)}{2})
所以答案就是

[sum^{ileq n,iin mathrm{odd}}_{i=1}varphi(i)+sum^{ileq n,iinmathrm{even}}_{i=2}2varphi(i)-1 ]

要乘二的原因是对于 (p(a,b))(p(b,a)) 两组合法解,我们只计算了其中一种(也就是 (a>b) 那种)。而减一则是因为 (p(1,1)) 被计算了,要舍去。
考虑怎么计算上述式子。假设我们已经求出了 ([1,n]) 中,偶数的 (varphi) 和奇数的 (varphi) 各自的和,我们需要将它扩展到 ([1,2n])
对于任意的奇数 (x),它乘二之后会变成偶数。假设原来 (varphi(x)=x imes frac{p_1-1}{p_1} imes frac{p_2-1}{p_2}cdots),由于 (2) 是一个 (x) 之前没有的因子,所以 (varphi(2x)=2x imes frac{p_1-1}{p_1} imes frac{p_2-1}{p_2}cdots imes frac{1}{2}),依然等于 (varphi(x))
对于任意的偶数 (x),它乘二之后并没有多出任何之前不存在的质因子,所以 (varphi(2x)=2x imes frac{p_1-1}{p_1} imes frac{p_2-1}{p_2}cdots=2varphi(x))
所以 ([1,2n]) 中偶数的 (varphi) 之和等于 (s_{odd}+2s_{even})
然后我们用杜教筛求出 ([1,2n]) 所有数的 (varphi) 之和,用该值减去偶数的 (varphi) 之和就得到了奇数的 (varphi) 之和。再回溯计算即可。
时间复杂度 (O(Tn^{frac{2}{3}}log n))

代码

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;

const int N=1e7+10;
int Q,m,prm[N];
ull n,s1,s2,phi[N];
bool v[N];
map<int,ull> sphi;

void findprm(int n)
{
	phi[1]=1;
	for (int i=2;i<=n;i++)
	{
		if (!v[i]) prm[++m]=i,phi[i]=i-1;
		for (int j=1;j<=m;j++)
		{
			if (i>n/prm[j]) break;
			v[i*prm[j]]=1; phi[i*prm[j]]=phi[i]*(prm[j]-1);
			if (i%prm[j]==0)
			{
				phi[i*prm[j]]=phi[i]*prm[j];
				break;
			}
		}
	}
}

ull sumphi(ull n)
{
	if (n<N) return phi[n];
	if (sphi[n]) return sphi[n];
	ull res=114514;
	if (n&1ULL) res=(n+1ULL)/2ULL*n;
		else res=n/2ULL*(n+1ULL);
	for (ull l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		res-=sumphi(n/l)*(r-l+1);
	}
	return sphi[n]=res;
}

void calc(ull n,ull &s1,ull &s2)
{
	if (n==1)
	{
		s1=1; s2=0;
		return;
	}
	calc(n/2ULL,s1,s2);
	s2=s1+s2*2ULL; s1=sumphi(n)-s2;
}

int main()
{
	findprm(N-1);
	for (int i=1;i<N;i++)
		phi[i]=phi[i-1]+phi[i];
	scanf("%d",&Q);
	while (Q--)
	{
		cin>>n;
		calc(n,s1,s2);
		cout<<s1+s2*2ULL-1ULL<<endl;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/14086012.html