zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

      

  • 相关阅读:
    Norton我错怪了你啊~~
    RUNRMTCMD命令使用
    如何查看QTEMP的内容?可以查看别人的QTEMP的
    关于文件的ShareODP和USROPN
    虚拟主机权限之log4net
    如何向远程系统提交命令?
    在5250上面实现复制粘贴
    php与数据库对应实体类的命名
    Action Script 中的 super
    Linux下源码编译方式安装MySQL5.5.12(转)
  • 原文地址:https://www.cnblogs.com/carcar/p/12391626.html
Copyright © 2011-2022 走看看