[题解]CodeForces1208G Polygons

CodeForces1208G Polygons

What an interesting problem QuuuuQ...

题目描述

给出一个圆,找出k个边长在\([3,n]\)范围内且互不相同的正多边形,通过旋转使得总的顶点个数最少。问最少的顶点个数

\(3 \leq n \leq 10^6,1 \leq k \leq n-2\)

Solution

amazing~.

首先,手模一下可以发现,假设我们选择了边长为\(l\) 的正多边形,那么,选择所有边长为\(l\)的因数的正多边形一定只会更优,因为在这种情况下不会增加点的个数

然后,所有多边形至少有一个公共点,显然,记这个点为P

那么,假设圆的周长为1,记圆上每一个点的位置为顺时针方向距离P的距离

对于一个正\(l\)边形,它的顶点就是\(0,\frac{1}{l},\frac{2}{l},...,\frac{l-1}{l}\),最终的答案就是不同的最简分数的个数。而对于l,如果分母和分子不互质,那么变成最简分数后分母就是\(l\)的一个因子\(x\),这个点已经被正\(x\)变形算过了,所以对于\(l\),新增的点的个数就是\(\phi (l)\).

注意没有2边形,所以需要特判


关于欧拉函数\(\phi\)

\(\phi (x)=x*\prod_{i=1}^{n} 1-\frac{1}{p_i}\),其中,p是x的质因数

可以利用埃式筛法求欧拉函数

void INIT(){
	int cnt=0;
	a[1].val=a[1].num=1;
	rep(i,2,n){
		a[i].num=i;
		if(!vis[i])p[++cnt]=i,a[i].val=i-1;
		for(int j=1;j<=cnt&&p[j]<=n/i;j++){
			vis[i*p[j]]=1;
			if(i%p[j]==0){a[i*p[j]].val=a[i].val*p[j];continue;}
			a[i*p[j]].val=a[i].val*(p[j]-1);
		}
	}
}

Code

#include<bits/stdc++.h>
#define rep(X,A,B) for(int X=A;X<=B;X++)
#define tep(X,A,B) for(int X=A;X>=B;X--)
#define LL long long
const int N=1000010;
const int M=2100010;
using namespace std;

int n,k,f[N],vis[N],p[N];

struct nn{
	int val,num;
}a[N];

int cmp(nn A,nn B){
	if(A.val==B.val)return (A.num&1)>(B.num&1);
	return A.val<B.val;
}

void INIT(){
	int cnt=0;
	a[1].val=a[1].num=1;
	rep(i,2,n){
		a[i].num=i;
		if(!vis[i])p[++cnt]=i,a[i].val=i-1;
		for(int j=1;j<=cnt&&p[j]<=n/i;j++){
			vis[i*p[j]]=1;
			if(i%p[j]==0){a[i*p[j]].val=a[i].val*p[j];continue;}
			a[i*p[j]].val=a[i].val*(p[j]-1);
		}
	}
}

void SOLVE(){
	LL ans=0;
	int flg=0;
	sort(a+1,a+n+1,cmp);
	rep(i,3,k+2){
		//printf("a[%d]=%d %d\n",i,a[i].val,a[i].num);
		ans+=1LL*a[i].val;
		if(a[i].num%2==0)flg=1;
	}
	printf("%lld\n",ans+flg+1);
}

int main(){
	scanf("%d%d",&n,&k);
	INIT();
	SOLVE();
	return 0;
}
posted @ 2019-09-27 19:36  硫氯  阅读(147)  评论(0编辑  收藏  举报