[题解]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;
}