Codeforces Round #622 (Div. 2)D(离散化,状压DP)

 1 #define HAVE_STRUCT_TIMESPEC
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 int bit[1<<9];
 5 set<int>s;
 6 pair<int,int>a[200007];
 7 int pre[10];
 8 int dp[1<<9];
 9 int pos[200007];
10 int main(){
11     ios::sync_with_stdio(false);
12     cin.tie(NULL);
13     cout.tie(NULL);
14     int n,m,k;
15     cin>>n>>m>>k;
16     for(int i=1;i<=n;++i){
17         int x,y;
18         cin>>x>>y;
19         a[2*i-1]={x,i};//记录线段端点位置
20         a[2*i]={y+1,-i};//前缀相减,故存右端点时+1
21     }
22     for(int i=0;i<=k;++i)
23         pre[i]=1<<i;//二进制下第i位为1的数字大小
24     for(int i=1;i<pre[k];++i){
25         bit[i]=bit[i>>1]^(i&1);//把i在二进制下为1的个数为奇数的bit[i]变为1
26         dp[i]=-1e9;
27     }
28     sort(a+1,a+1+2*n);
29     int last=0;//前一个端点位置
30     for(int i=0;i<k;++i)
31         s.insert(i);//每条线段给一个编号
32     for(int i=1;i<=2*n;++i){
33         int now=a[i].first;
34         int temp=a[i].second;
35         for(int j=1;j<pre[k];++j)
36             dp[j]+=bit[j]*(now-last);//当前情况下线段数为奇数的可以加上这一段线段的长度
37         last=now;//这个端点用过了,记下他的位置
38         if(temp>0){//这个端点是左端点
39             pos[temp]=*s.begin();//去集合里领取一条线段的编号,记作当前线段的编号
40             s.erase(pos[temp]);
41             for(int j=0;j<pre[k];++j)//枚举所有情况
42                 if(j&pre[pos[temp]])//包含这条线段的情况
43                     dp[j]=max(dp[j],dp[j^pre[pos[temp]]]);//更新最大值
44         }
45         else{//这个端点是右端点
46             temp=-temp;
47             s.insert(pos[temp]);//这条线段用完了还给集合
48             for(int j=0;j<pre[k];++j)//枚举所有情况
49                 if(j&pre[pos[temp]]){//包含这条线段的情况
50                     dp[j^pre[pos[temp]]]=max(dp[j^pre[pos[temp]]],dp[j]);//更新最大值
51                     dp[j]=-1e9;//这条线段不取,包含这条线段的情况初始化
52                 }
53         }
54     }
55     cout<<dp[0];//所有线段都遍历一遍以后,所有线段都不取,dp[0]为扫过一遍的答案
56     return 0;
57 }

 

posted @ 2020-03-02 20:49  sewage  阅读(200)  评论(0编辑  收藏  举报