【洛谷P6860】象棋与马

题目

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

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

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

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

\[\left ( \sum_{a=1}^n\sum_{b=1}^np(a,b) \right )\bmod\ 2^{64} \]

的值。

思路

\[\mathrm{Q\color{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^{i\leq n,i\in \mathrm{odd}}_{i=1}\varphi(i)+\sum^{i\leq n,i\in\mathrm{even}}_{i=2}2\varphi(i)-1 \]

要乘二的原因是对于 \(p(a,b)\)\(p(b,a)\) 两组合法解,我们只计算了其中一种(也就是 \(a>b\) 那种)。而减一则是因为 \(p(1,1)\) 被计算了,要舍去。
考虑怎么计算上述式子。假设我们已经求出了 \([1,n]\) 中,偶数的 \(\varphi\) 和奇数的 \(\varphi\) 各自的和,我们需要将它扩展到 \([1,2n]\)
对于任意的奇数 \(x\),它乘二之后会变成偶数。假设原来 \(\varphi(x)=x\times \frac{p_1-1}{p_1}\times \frac{p_2-1}{p_2}\cdots\),由于 \(2\) 是一个 \(x\) 之前没有的因子,所以 \(\varphi(2x)=2x\times \frac{p_1-1}{p_1}\times \frac{p_2-1}{p_2}\cdots\times \frac{1}{2}\),依然等于 \(\varphi(x)\)
对于任意的偶数 \(x\),它乘二之后并没有多出任何之前不存在的质因子,所以 \(\varphi(2x)=2x\times \frac{p_1-1}{p_1}\times \frac{p_2-1}{p_2}\cdots=2\varphi(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;
}
posted @ 2020-12-04 15:19  stoorz  阅读(134)  评论(0编辑  收藏  举报