题目链接
题目思路
如何最大化收不到礼物的人数?对于一个偶环,假设长度为 k。那么只要有 k / 2 个人忘带礼物,k 个人就全都收
不到礼物。对于一个奇环,假设长度为 k。那么需要有 (k + 1) / 2 个人忘带礼物,k 个人就会都收不到礼物。贪心
即可。
如何最小化收不到礼物的人数?如果有一个大小为 m 的环,只要让这 m 个人都忘带,就只会有 m 个人收不到礼
物。因此如果能找到若干个环,使得它们的长度之和刚好是 k,那么答案就是 k。否则会有一个环不能被完全覆
盖,还会再牵连一个人,答案就是 k + 1
这个可以用二进制优化dp 那么复杂度最坏为(nsqrt n) 但是有点卡常 对于存不存在问题用个(bitset)可以优化一个(w)
最后的复杂度为(frac{nsqrt n}{w})
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug printf(" I am here
");
using namespace std;
#define S dp
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
mt19937 rnd(time(0));
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-10;
int n,k;
int a[maxn],vis[maxn];
int num[maxn];
int cnt,tot;
int ma,mi;
bitset<maxn> dp;
signed main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
if(vis[i]) continue;
int x=i,sum=0;
while(!vis[x]){
vis[x]=1;
x=a[x];
sum++;
}
num[sum]++;
if(sum%2==1) tot++;
}
if(2*k<=n-tot){
ma=2*k;
}else{
ma=min(n,(n-tot)+(k-(n-tot)/2));
}
dp[0]=1;
for(int i=1;i<=1e6;i++){
if(num[i]==0) continue;
vector<int> vec;
for(int j=0;(1<<j)<=num[i];j++){
vec.push_back(1<<j);
num[i]-=(1<<j);
}
if(num[i]){
vec.push_back(num[i]);
}
for(auto x:vec){
dp=(dp|(dp<<x*i));
}
}
if(dp[k]){
mi=k;
}else{
mi=k+1;
}
printf("%d %d
",mi,ma);
return 0;
}