F. PolandBall and Gifts 题解(贪心+二进制优化多重背包+bitset)

题目链接

题目思路

如何最大化收不到礼物的人数?对于一个偶环,假设长度为 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;
}
卷也卷不过,躺又躺不平
原文地址:https://www.cnblogs.com/hunxuewangzi/p/15176285.html