「ZJOI2022模拟赛二 A」在樱花树下 题解


题目大意

给定两个正整数 \(n,k\),你需要选出 \(3~n\)\(k\) 个不同的正整数 \(a_i\)
在二维平面上有一个圆,求至少需要在圆上钦定多少个点,使得对于你选出的任意一个 \(a_i\),都存在 \(a_i\) 个钦定的点能构成一个正 \(a_i\) 边形。
\(k+2\le n\le 10^6\)

题目解析

首先我们发现,假设这个圆周长为 \(1\) ,如果所有的点都在 \(0\) 处重合,那么对于任意的整数 \(k\in[0,a_i-1]\),圆上都存在点 \(\frac{k}{a_i}\)
通过反证法不难得出如果存在一个数字 \(a_i\) 被选中,那么所有的 \(a_i\) 的因数都被选中才是最优的。不难得出这是增加 \(\phi(a_i)\) 个点,由于一个数的约数的欧拉函数肯定比它小,所以直接按照欧拉函数从小到大排序然后求和即可。
考虑到 \(1,2\) , 不难发现 \(1\) 肯定会被选到,并且当 \(k\ge2\) 的时候 \(2\) 也会被选到。换句话说,当 \(k=1\) 的时候需要再加 \(1\),否则再加 \(2\)
欧拉函数可以通过一次欧拉筛来求。复杂度 \(O\left(n\log n\right)\),瓶颈在于排序。

#include
#define db double
#define gc getchar
#define pc putchar
#define U unsigned
#define ll long long
#define ld long double
#define ull unsigned long long
#define Tp template
#define Me(a,b) memset(a,b,sizeof(a))
Tp _T mabs(_T a){ return a>0?a:-a; }
Tp _T mmax(_T a,_T b){ return a>b?a:b; }
Tp _T mmin(_T a,_T b){ return a9) print(x/10); pc((x%10)+48); return; }
#define EPS (1e-7)
#define INF (0x7fffffff)
#define LL_INF (0x7fffffffffffffff)
#define maxn 539
#define maxm
#define MOD
#define Type int
#ifndef ONLINE_JUDGE
//#define debug
#endif
using namespace std;
Type read(){
	char c=gc(); Type s=0; int flag=0;
	while((c<'0'||c>'9')&&c!='-') c=gc(); if(c=='-') c=gc(),flag=1;
	while('0'<=c&&c<='9'){ s=(s<<1)+(s<<3)+(c^48); c=gc(); }
	if(flag) return -s; return s;
}
int n,m,h[maxn][maxn];
int f[maxn][maxn],flag[maxn];
struct JTZ{ int l,r; }a[maxn];
int fx[4]={0,0,1,-1}; int fy[4]={-1,1,0,0};
void dfs(int x,int y){
	int i,tx,ty; for(i=1;i<=4;i++){
		tx=fx[i]+x; ty=fy[i]+y;
		if(tx<1||tx>n||ty<1||ty>m||f[tx][ty]) continue;
		f[tx][ty]=1;  dfs(tx,ty);
	} return;
}

int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	n=read(); m=read(); int i,j,k;
	for(i=1;i<=n;i++) for(j=1;j<=m;j++) h[i][j]=read();
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++) for(k=1;k<=m;k++) f[j][k]=0;
		f[1][i]=1; dfs(1,i);
		for(i=1;i<=m;i++){
			if(f[n][i]) flag[i]=1;
			if(!a[i].l&&f[n][i]) a[i].l=i;
			if(f[n][i]) a[i].r=i;
		}
	}
	return 0;
}