1. 程式人生 > 其它 >F. PolandBall and Gifts 題解(貪心+二進位制優化多重揹包+bitset)

F. PolandBall and Gifts 題解(貪心+二進位制優化多重揹包+bitset)

題目連結

題目思路

如何最大化收不到禮物的人數?對於一個偶環,假設長度為 k。那麼只要有 k / 2 個人忘帶禮物,k 個人就全都收

不到禮物。對於一個奇環,假設長度為 k。那麼需要有 (k + 1) / 2 個人忘帶禮物,k 個人就會都收不到禮物。貪心

即可。

如何最小化收不到禮物的人數?如果有一個大小為 m 的環,只要讓這 m 個人都忘帶,就只會有 m 個人收不到禮

物。因此如果能找到若干個環,使得它們的長度之和剛好是 k,那麼答案就是 k。否則會有一個環不能被完全覆

蓋,還會再牽連一個人,答案就是 k + 1

這個可以用二進位制優化dp 那麼複雜度最壞為\(n\sqrt n\) 但是有點卡常 對於存不存在問題用個\(bitset\)

可以優化一個\(w\)

最後的複雜度為\(\frac{n\sqrt n}{w}\)

程式碼

#include<bits/stdc++.h>
#define fi first
#define se second
#define debug printf(" I am here\n");
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\n",mi,ma);
    return 0;
}
卷也卷不過,躺又躺不平