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 k≥2 时我们必选 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;
}