「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;
}