Polygons

1.前言

一道好题 /kk

2.题解

考虑加入边数为 x x x 的多边形。

首先有一个结论,所有多边形靠在一个点上是一种最优方案。对于一个边数为 x x x 的多边形,令这个点的编号为 x n x_n xn,然后顺时针编号为 x 1 , x 2 , x 3 , x 4 . . . x_1,x_2, x_3, x_4... x1,x2,x3,x4...

证明比较显然;

由于是正多边形,那么考虑边数分别为 i , j i, j i,j 的两个多边形,无论以哪两个点靠在一起,重复的点数永远都是不变的。

然后我们发现,当我想加入正 x x x 边形时,如果有点 x y x_y xy gcd ⁡ ( x , y ) ≠ 1 \gcd (x, y) \neq 1 gcd(x,y)=1)没有被覆盖,那么我们肯定会选择一个 x gcd ⁡ ( x , y ) \frac{x}{\gcd (x, y)} gcd(x,y)x 边形,因为 x gcd ⁡ ( x , y ) \frac{x}{\gcd (x, y)} gcd(x,y)x 边形所有的点都在 x x x 边形上,而它的总点数没有 x x x 边形多,所以选它一定不会更劣,那么我们加入正 x x x 边形的代价就为 ϕ ( x ) \phi (x) ϕ(x),按照 ϕ ( x ) \phi (x) ϕ(x) 从小到大排序即可。

注意没有 1 , 2 1, 2 1,2 边形,如果 k = 1 k = 1 k=1 时我们必选 3 3 3 边形, k ≥ 2 k \geq 2 k2 时我们必选 3 , 4 3, 4 3,4 边形,需要把 “ 1 , 2 1, 2 1,2 边形”少算的贡献加上。

#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define fi first
#define se second
#define db double
#define LL long long
#define int long long
#define PII pair <int, int>
#define ULL unsigned long long
#define MP(x,y) make_pair (x, y)
#define rep(i,j,k) for (int i = (j); i <= (k); i++)
#define per(i,j,k) for (int i = (j); i >= (k); i--)

template <typename T>
void read (T &x) {
    x = 0; T f = 1; 
    char ch = getchar ();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar ();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar ();
    }
    x *= f;
}
template <typename T, typename... Args>
void read (T &x, Args&... Arg) {
    read (x), read (Arg...);
}
const int MaxPrint = 1000;
int Poi_For_Print, Tmp_For_Print[MaxPrint + 5];
template <typename T>
void write (T x) {
	if (x == 0) {
		putchar ('0');
		return;
	}
    bool flag = (x < 0 ? 1 : 0);
    x = (x < 0 ? -x : x);
    while (x) Tmp_For_Print[++Poi_For_Print] = x % 10, x /= 10;
    if (flag) putchar ('-');
    while (Poi_For_Print) putchar (Tmp_For_Print[Poi_For_Print--] + '0');
}
template <typename T, typename... Args>
void write (T x, Args... Arg) {
    write (x); putchar (' '); write (Arg...);
}
template <typename T, typename... Args>
void print (T x, char ch) {
    write (x); putchar (ch);
}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }

const int Maxn = 1e6;

int n, k;
int poi, a[Maxn + 5];

int cnt, primes[Maxn + 5];
int phi[Maxn + 5];
bool vis[Maxn + 5];
void Euler () {
	phi[1] = 1;
    rep (i, 2, Maxn) {
        if (!vis[i]) {
            primes[++cnt] = i;
            phi[i] = i - 1;
        }
        rep (j, 1, cnt) {
            if (primes[j] > Maxn / i) break;
            vis[i * primes[j]] = 1;
            if (i % primes[j] == 0) {
                phi[i * primes[j]] = phi[i] * primes[j];
                break;
            }
            phi[i * primes[j]] = phi[i] * (primes[j] - 1);
        }
    }
}

signed main () {
//    freopen ("C:\\Users\\Administrator\\Desktop\\lihan\\1.in", "r", stdin);
//    freopen ("C:\\Users\\Administrator\\Desktop\\lihan\\1.out", "w", stdout);

    Euler ();
    read (n, k);
    rep (i, 3, n) a[++poi] = phi[i];
    sort (a + 1, a + 1 + poi);

    int res = 0;
    rep (i, 1, k) {
        res += a[i];
    }
    if (k == 1) write (3);
	else write (res + 2);
    return 0;
}
posted @ 2022-07-15 17:05  C2022lihan  阅读(62)  评论(0编辑  收藏  举报