CF1313D Happy New Year

挺有意思一题,对我挺有启发性的。

比我小又比我强的 George 不看题解都会做,我是看了他的题解才会做。 😭😭😭😭😭😭

题解

首先必然是可以离散化的。

我们考虑到应该是 \(\text{dp}\) ,但是发现不知道怎么样才能够在数组中储存足够的信息。

我们发现 \(k\le 8\) ,应该从这里入手。所以我们可以利用状压来储存这一位置选择集合为 \(j\) 的咒语时最大可以时多少,然后根据定义转移就可以了。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,K=8;
int n,m,k,maxn=0;
struct Opt{int flag,val,id;}a[N<<1];
int f[N<<1][1<<K],bag[K];
bool cmp(Opt a,Opt b){
	if(a.val!=b.val) return a.val<b.val;
	return a.flag<b.flag;
}
int cnt(int x){
	int res=0;
	while(x) res^=(x&1),x>>=1;
	return res;
}
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;++i){
		scanf("%d%d",&a[i].val,&a[i+n].val),a[i+n].val++;
		a[i+n].flag=-1,a[i].flag=1,a[i].id=a[i+n].id=i;
	}
	sort(a+1,a+1+n+n,cmp);
	for(int i=1;i<=n+n;++i){
		if(a[i].flag>0){
			int now=-1;
			for(int j=0;j<k;++j) if(!bag[j]){bag[j]=a[i].id,now=j;break;}
			for(int j=0;j<(1<<k);++j){
				if((j&maxn)!=j) continue;
				f[i][j]=max(f[i][j],f[i-1][j]+cnt(j)*(a[i].val-a[i-1].val));
				f[i][j^(1<<now)]=max(f[i][j^(1<<now)],f[i-1][j]+cnt(j)*(a[i].val-a[i-1].val));
			}
			maxn^=(1<<now);
		}
		else{
			int now=-1;
			for(int j=0;j<k;++j) if(bag[j]==a[i].id){now=j;break;}
			for(int j=0;j<(1<<k);++j){
				if((j&maxn)!=j) continue;
				if(j&(1<<now)) f[i][j^(1<<now)]=max(f[i][j^(1<<now)],f[i-1][j]+cnt(j)*(a[i].val-a[i-1].val));
				else f[i][j]=max(f[i][j],f[i-1][j]+cnt(j)*(a[i].val-a[i-1].val));
			}
			maxn^=(1<<now),bag[now]=0;
		}
	}
	return printf("%d\n",f[n+n][0]),0;
}
posted @ 2021-04-20 10:00  Point_King  阅读(95)  评论(0)    收藏  举报