「题解」Codeforces 755F PolandBall and Gifts
do_while_true · · 题解
orz qyc
来我的cnblogs中获得应该会更好的体验
看成一个人
最大值发现可以贪心,偶数长度的环可以用长度除以
最小值的话,每个环第一次开始染它色一定是贡献为
发现对于一个长度为
问题转化为给定若干个正整数
发现 bitset 和分治 NTT 都不大能过,注意到对
再加个二进制分组优化,时间复杂度大概是个
有一个有理有据的方法是类似根号分治,选择一个值域
后面那个做法的复杂度为
代码是前面没有根号分治的做法。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<bitset>
typedef long long ll;
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; }
template <typename T> T chkmax(T &x, T y) { return x = x > y ? x : y; }
template <typename T>
T &read(T &r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = (r << 3) + (r <<1) + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
const int N = 1000010;
int n, p[N], a[N], m, k, ans1, ans2;
bool vis[N];
int ct[N], b[N], c[N], us[N];
std::bitset<1000001>f;
void dfs(int x, int s) {
if(vis[x]) {
a[++m] = s;
return ;
}
vis[x] = 1;
dfs(p[x], s+1);
}
signed main() {
read(n); read(k); int _n = n;
for(int i = 1; i <= n; ++i) read(p[i]);
for(int i = 1; i <= n; ++i)
if(!vis[i])
dfs(i, 0);
n = m;
std::sort(a + 1, a + n + 1);
int k_ = k;
for(int i = 1; i <= n; ++i) {
if(!k_) break ;
int t = Min(a[i] / 2, k_);
ans2 += t * 2; k_ -= t;
}
for(int i = 1; i <= n; ++i)
if((a[i] & 1) && k_)
++ans2,
--k_;
//
for(int i = 1; i <= _n; ++i) ct[a[i]]++;
m = 0;
for(int i = 1; i <= _n; ++i)
if(ct[i])
b[++m] = i,
c[m] = ct[i];
f[0] = 1;
for(int i = 1; i <= m; ++i) {
int tc = c[i];
for(int j = 1; tc; j <<= 1) {
int t = Min(j, tc);
f |= f << (b[i] * t),
tc -= t;
}
}
if(f[k]) ans1 = k;
else ans1 = k+1;
printf("%d %d\n", ans1, ans2);
return 0;
}