2190 - [SDOI2008]仪仗队

题解bymod998244353

我们可以假设C君的位置为(0,0),建立一个平面直角坐标系。

那么队伍可以看做是一个(0,0)\rightarrow(n-1,n-1)n\times n的矩阵。

我们可以不考虑(0,1)(1,0),最后在加上,就变成(1,1)\rightarrow(n-1,n-1)(n-1)\times(n-1)的矩阵。

我们可以发现整个图形是对称的,所以只用算一半,乘上2,再减去重复计算的(1,1),我们就来算满足b\leq a的那一半。

我们可以发现,对于一个点(a,b),当\gcd(a,b)>1时,会被(\dfrac{a}{\gcd(a,b)},\dfrac{b}{\gcd(a,b)})挡住,例如(4,2)会被(2,1)挡住。(原理为相似三角形)

所以能看到的(a,b)都有\gcd(a,b)=1

f_a表示满足(a,b)能被看到的b有几个(1\leq b\leq a\leq n-1)。

则这一半的个数为\sum\limits_{a=1}^n f_a,整个的答案就是2(\sum\limits_{a=1}^n f_a)-1+2=2(\sum\limits_{a=1}^n f_a)+1

\gcd(a,b)=1,b\leq a得,f_a就是表示小于等于n且与n互质的数的个数,即\varphi(a),那么我们就把\varphi线性筛出来再求和即可。

注意要特判n=1的情况

#include <bits/stdc++.h>
using namespace std;
const int MAXN=40005;
bool isp[MAXN];
int prime[MAXN],pcnt,phi[MAXN],ans;
void init(int n) {
	ans=phi[1]=1;
	for(int i=2; i<=n; ++i) {//线性筛phi
		if(!isp[i]) {
			prime[++pcnt]=i;
			phi[i]=i-1;
		}
		for(int j=1,x; j<=pcnt&&(x=prime[j]*i)<=n; ++j) {
			isp[prime[j]*i]=1;
			if(i%prime[j]) {
				phi[x]=phi[i]*phi[prime[j]];
			} else {
				phi[x]=phi[i]*prime[j];
				break;
			}
		}
		ans+=phi[i];//顺便求和
	}
}
int main() {
	int n,q;
	scanf("%d",&n);
	init(--n);
	printf("%d\n",n==0?0:ans*2+1);//特判0
	return 0;
}