[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的主要内容,如果未能解决你的问题,请参考以下文章

CF 爆发者

[CF930E]/[CF944G]Coins Exhibition

CF怎么改名

dp专题

Codeforces | CF1028C Rectangles

Codeforces 刷题记录