codeforces#1313D. Happy New Year(扫描线+dp)

题目链接:

https://codeforces.com/contest/1313/problem/D

题意:

有$n$个操作,每个操作可以使得一段区间的小朋友糖果数加一

如果所有操作都执行的话,每个小朋友最多得到$k$个糖果。得到糖果数为奇数的小朋友会很开心,求最多使多少个小朋友开心

分析:

这题有点难,所以思考了半个小时没思路就看了$cf$的官方题解,然后结合排行榜的代码,终于理解了这题的做法

这道题目用到了扫描线算法,有$2n$个事件,定义$dp[i][j]$为第$i$个事件时,在所有覆盖当前段的操作中,选择状态为$j$的操作集合。如果某位为1,那么对应的操作被选上了

这个转移有点特殊,所以不再赘述,解法可以看代码

 

我们可以考虑如果小朋友数量最大不是$1e9$,我们按照每个小朋友来$dp$,而不是按照事件来$dp$,那么我们可以为$dp[i][j]+1$如果$j$是奇数状态,否则不变,如果一个区间结束了,我们可以释放对应状态的标记,最后肯定释放了所有位置,所以结果就是$dp[0]$了

 AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (int i=(a);i<=(b);i++)
#define per(i,a,b) for (int i=(b);i>=(a);i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())

typedef long long ll;
typedef vector<int> VI;
typedef pair<int,int> PII;

const int maxn=1e5+7;
const int INF=0x3f3f3f3f;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}

int sk[(1<<8)+7],sksz,n,m,k;
int dp[(1<<8)+7],idtocnt[maxn*2],used[(1<<8)+7];


struct Quer{
    int x,type,id;
    bool operator <(const Quer other)const{
        if(x!=other.x)return x<other.x;
        else return type<other.type;
    }
}quer[maxn*2];



int main() {
    scanf("%d %d %d",&n,&m,&k);
    rep(i,1,n){
        int l,r;
        scanf("%d %d",&l,&r);
        quer[i*2]={l,1,i};
        quer[i*2-1]={r+1,-1,i};
    }
    //初始化dp数组和计算1的数量为奇数的二进制的集合
    rep(i,0,(1<<k)-1){
        dp[i]=-INF;
        int tem=i,cnt=0;
        while(tem){
            if(tem%2)cnt++;
            tem/=2;
        }
        if(cnt%2)sk[++sksz]=i;
    }
    dp[0]=0;
    sort(quer+1,quer+1+2*n);
    int prex=0;
    rep(i,1,2*n){

        Quer now=quer[i];
//        cout<<now.x<<" "<<now.type<<endl;
        rep(j,1,sksz){
            if(dp[sk[j]]==-INF)continue;
            dp[sk[j]]+=(now.x-prex);
        }
        prex=now.x;
        if(now.type==1){
            int cnt=0;
            while(used[cnt])cnt++;
            used[cnt]=1;
            idtocnt[now.id]=cnt;
            rep(mask,0,(1<<k)-1){
                if((mask&(1<<cnt))==0)
                    dp[mask^(1<<cnt)]=dp[mask];
            }

        }else{
            int cnt=idtocnt[now.id];
            used[cnt]=0;
            rep(mask,0,(1<<k)-1){
                if(mask&(1<<cnt)){
                    dp[mask^(1<<cnt)]=max(dp[mask],dp[mask^(1<<cnt)]);
                    dp[mask]=-INF;
                }
            }
        }
//        rep(j,0,7)cout<<dp[j]<<" ";
//        cout<<endl;
    }
    printf("%d
",dp[0]);
    return 0;
}

  

  

原文地址:https://www.cnblogs.com/carcar/p/12391626.html