题解 CF1111C 【Creative Snap】

看了那么多大佬的线段树题解,本萌新瑟瑟发抖,那么就写一篇卡常能过的dfsdfs题解吧

首先,对于每一段区间,我们可以用树状数组来维护其中的复仇者数量,然后讨论如何炸毁这段区间:

如果其中没有复仇者,直接炸毁即可

要不然把区间分成两段,枚举每一段是直接炸毁还是继续dfsdfs下去,最后取答案的最小值即可

但是注意一下数据范围

1n301≤n≤30

这样树状数组一定会MLEMLE

那用mapmap代替数组?

复杂度多了一个loglog,又TLETLE

那么我们就要用一种神奇的数据结构了:tr1::unordered_map,它和map的用法一模一样,而且复杂度是O(1)O(1)

我们这样就愉快的通过这道题了

code:

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#pragma GCC optimize(3)
using namespace std;

#define int long long
int n,k,A,B,ans,a[100002],l;
tr1::unordered_map<int,int>tt;
void add2(int s,int v){
	for(int i=s;i<=l+5;i+=(i&-i)){
		tt[i]+=v;
	}
}
int ask2(int s){
	int sum=0;
	for(int i=s;i;i-=(i&-i))sum+=tt[i];
	return sum; 
}
int work2(int l,int r){
	int xr=ask2(r),xl=ask2(l-1);
	if(xr-xl==0){
		return A;
	}
	if(l==r){
		return B*(xr-xl);
	}
	int mid=(l+r)/2;
	int a1=work2(l,mid),a2=work2(mid+1,r);
	int b1=B*(mid-l+1)*(ask2(mid)-xl),b2=B*(r-mid)*(xr-ask2(mid));
	if(b1==0)b1=1e8;
	if(b2==0)b2=1e8;
	return min(B*(r-l+1)*(xr-xl),min(a1+b2,min(b1+a2,a1+a2)));
} 
main(){
	scanf("%lld%lld%lld%lld",&n,&k,&A,&B);
	l=pow(2,n);
	for(int i=1;i<=k;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=k;i++){
		add2(a[i],1);
	}
	printf("%lld\n",work2(1,l));
	return 0;
}
posted @ 2019-08-05 12:34  swiftqwq  阅读(9)  评论(0)    收藏  举报  来源