把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【CF1208G】Polygons(欧拉函数+贪心)

题目链接

  • 给定 \(n,k\),要求选择 \(3\sim n\)\(k\) 个不同的正整数 \(a_i\)
  • 给定一个圆,求至少需要在圆上选出多少个点,才能利用这些点构造出所有的正 \(a_i\) 边形。
  • \(3\le n\le10^6\)

最优构造方案

考虑对于已知的若干 \(a_i\),构造出至少需要多少的点。

首先肯定存在一种最优构造方案,满足所有多边形有一个共同顶点。以这个位置作为 \(0\),则正 \(d\) 边形对应的所有顶点位置依次为 \(0,\frac nd,2\times\frac nd,\cdots,(d-1)\times\frac nd\)

于是发现,\(0,\frac nd,2\times\frac nd,\cdots,(d-1)\times\frac nd\) 被标记,当且仅当存在 \(a_i\)\(d\) 的倍数。

除去一个数的因数的贡献后,就变成若存在 \(a_i\)\(d\) 的倍数,就能产生 \(\phi(d)\) 的贡献。

贪心选择

根据上面的结论,由于选择一个数会让它的所有因数都被标记,我们肯定优选选择它的因数。那么选择一个数 \(x\) 后新被标记的就只有它自身,也就是带来 \(\phi(x)\) 的贡献。

所以只要将所有 \(\phi(x)\) 排序,从小到大选择即可。(显然一个数的因数的 \(\phi\) 一定比它小)

注意特殊考虑标记 \(1\)\(2\),其中 \(1\) 一定会被标记,\(2\)\(k\ge 2\) 的时候会被标记(第一个选择 \(3\);第二个选择 \(4\)\(6\),二者都是 \(2\) 的倍数)。

代码:\(O(n\log n)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 1000000
using namespace std;
int n,k,Pt,P[N+5],phi[N+5];I void Sieve(CI n)//线性筛预处理欧拉函数
{
	phi[1]=1;for(RI i=2,j;i<=n;++i) for(!P[i]&&(phi[P[++Pt]=i]=i-1),j=1;j<=Pt&&i*P[j]<=n;++j)
		if(P[i*P[j]]=1,i%P[j]) phi[i*P[j]]=phi[i]*(P[j]-1);else {phi[i*P[j]]=phi[i]*P[j];break;} 
}
int main()
{
	RI i;long long t=0;for(scanf("%d%d",&n,&k),Sieve(n),sort(phi+3,phi+n+1),i=3;i<=2+k;++i) t+=phi[i];//排序后贪心选择
	return ++t,k>=2&&++t,printf("%lld\n",t),0;//特殊考虑标记1和2
}
posted @ 2021-11-08 19:36  TheLostWeak  阅读(44)  评论(0编辑  收藏  举报