[cf 1208G] Polygons
Posted psimonw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[cf 1208G] Polygons相关的知识,希望对你有一定的参考价值。
题意
在圆周上画出\(k\)个内接正多边形,要求\(k\)个正多边形边数不同,且最大的边数不超过\(n\),使得总顶点数最小。
题解
神仙题反映了我不会数学的事实。
考虑如果选了一个正\(n\)边形,那么必定会选择满足\(m | n\)的正\(m\)边形。
在考虑到最优的方案中,一定会让所有多边形共同一个点。
考虑这个点为\(O\),设圆周长为1,则正\(n\)边形上的点到点\(O\)的圆上距离为
\[
\frac0n, \frac1n, \frac2n, \ldots, \fracn - 1n
\]
考虑因为选了正\(n\)边形时,一定会选择满足\(m | n\)的正\(m\)边形。
这相当于正\(n\)边形独自产生的贡献是分母为\(n\)的最简真分数的个数(除去\(\frac0n\))。
这样,为了选出\(k\)个正多边形,就要让选出的正多边形独自产生的贡献和最小。
这样只要排个序取前\(k\)小求和即可。
需要注意的是,由于没有“一边形”和“二边形”,但是它们依然符合我们上面的类比分析。
所以就可以令“一边形”的贡献为1(代表\(O\),即\(\frac0n\)),“二边形”的贡献为1(即\(\frac12\))。
在\(k > 1\)时,它们的贡献要囊括进来(在\(k = 1\)时,“二边形”不会产生贡献),但是由于没有“一边形”,“二边形”这种东西,所以不能算进\(k\)个正多边形里面。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, k; long long ans;
int p[N], phi[N]; bool vis[N];
vector <int> coe;
void sieve ()
for (int i = 2; i <= n; ++i)
if (!vis[i])
p[++p[0]] = i;
phi[i] = i - 1;
for (int j = 1; j <= p[0] && i * p[j] <= n; ++j)
vis[i * p[j]] = 1;
if (i % p[j] == 0)
phi[i * p[j]] = phi[i] * p[j];
break;
phi[i * p[j]] = phi[i] * (p[j] - 1);
int main ()
cin >> n >> k, sieve();
if (k == 1)
return puts("3"), 0;
for (int i = 3; i <= n; ++i)
coe.push_back(phi[i]);
sort(coe.begin(), coe.end());
for (int i = 0; i < k; ++i)
ans += coe[i];
cout << ans + 2 << endl;
return 0;
以上是关于[cf 1208G] Polygons的主要内容,如果未能解决你的问题,请参考以下文章
[CF930E]/[CF944G]Coins Exhibition