A two (Unaccepted)
题目大意 :
- 咕咕
Code
Show Code
B bracket (Unaccepted)
题目大意 :
- 咕咕
Code
Show Code
C sum
题目大意 : 从1到n中选一个子集,满足元素间两两互质,最大化子集和
-
有一个没证明但是感觉很对的结论是答案子集中每个元素质因子分解后不质因子种类最多两个,而且一个小于根号,一个大于根号
, -
那就先只用一种质因子,s给小于根号的质数建边权为0的边,大于根号的质数给t建边权为0的边
-
然后如果有两个质因子可以更优,那就给这两个点建一条边权位多出来的贡献的边
-
跑一遍最大费用可行流,再加上一个质数的贡献
Code
Show Code
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
struct Edge {
int n, t, f, c;
}e[N*5];
int h[N], edc = 1;
void Add(int x, int y, int z) {
e[++edc] = (Edge) {h[x], y, 1, z}; h[x] = edc;
e[++edc] = (Edge) {h[y], x, 0,-z}; h[y] = edc;
}
bool v[N];
int n, p[N], f[N], tot, sq, ans, d[N];
int Cal(int x, ll y) {
while (y * x <= n) y *= x;
return y;
}
bool Spfa() {
memset(v + 1, 0, tot);
memset(d + 1, 0xcf, tot * 4);
queue<int> q; q.push(1); d[1] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x], y; i; i = e[i].n) {
if (!e[i].f || d[y=e[i].t] >= d[x] + e[i].c) continue;
d[y] = d[x] + e[i].c; q.push(y);
}
}
return d[2] > 0;
}
int Dinic(int x, int lim) {
if (x == 2) return lim;
int sum = 0; v[x] = 1;
for (int i = h[x], y; i && lim; i = e[i].n)
if (e[i].f && d[y=e[i].t] == d[x] + e[i].c && !v[y])
if (Dinic(y, 1)) sum++, e[i].f--, e[i^1].f++, ans += e[i].c;
if (!sum) d[x] = -1e9;
return sum;
}
int main() {
scanf("%d", &n); tot = 2; sq = sqrt(n);
for (int i = 2; i <= n; ++i) {
if (!v[i]) {
p[++tot] = i;
f[tot] = Cal(i, i); ans += f[tot];
if (i <= sq) Add(1, tot, 0);
else Add(tot, 2, 0);
}
for (int j = 3; j <= tot && i * p[j] <= n; ++j) {
v[i*p[j]] = 1;
if (i % p[j] == 0) break;
}
}
for (int i = 3; p[i] <= sq; ++i)
for (int j = tot, tmp; p[j] > sq; --j)
if ((tmp = Cal(p[i], p[j]) - f[i] - f[j]) > 0)
Add(i, j, tmp);
while (Spfa()) Dinic(1, 1e9);
printf("%d
", ans + 1);
return 0;
}