有没有dalao指出我错在哪
查看原帖
有没有dalao指出我错在哪
312743
phelixzhen楼主2022/9/29 21:18

思路是预处理出每个人去前边和后面的沿途不高兴和,然后对他们的差从小到大排序一下,枚举前面的保密室的最终人数,然后求个前缀和和后缀和。能过样例,但是只有14分。除了数据范围(可能爆long long)还有什么地方不太对吗?求调。

#include<bits/stdc++.h>
using namespace std;
#define ls (nw<<1)
#define rs ((nw<<1)|1)
#define mid ((l+r)>>1)
typedef long long ll;
const ll N=1e5+10,M=6e5+10;
ll n,t[N],m,A,B,ans=1e18,sum,pres[M],sufs[M];
struct stu{
	ll pre,suf,bh;
}s[M];
bool a[N][7];
bool cmp(const stu &a1,const stu &a2){
	return a1.suf-a1.pre>a2.suf-a2.pre;
}
void build_tree(ll nw,ll l,ll r){
	if(l==r){
		t[nw]=2;
		return;
	}
	build_tree(ls,l,mid);
	build_tree(rs,mid+1,r);
	t[nw]=t[ls]+t[rs];
}
void update(ll nw,ll l,ll r,ll x){
	if(l==r){
		t[nw]--;
		return;
	}
	if(x<=mid){
		update(ls,l,mid,x);
	}
	else{
		update(rs,mid+1,r,x);
	}
	t[nw]=t[ls]+t[rs];
}
ll query(ll nw,ll l,ll r,ll x,ll y){
	if(x<=l&&y>=r){
		return t[nw];
	}
	ll ans=0;
	if(x<=mid){
		ans+=query(ls,l,mid,x,y);
	}
	if(y>mid){
		ans+=query(rs,mid+1,r,x,y);
	}
	return ans;
}
signed main(){
	scanf("%lld %lld %lld %lld",&n,&m,&A,&B);
	build_tree(1,1,n);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=6;j++){
			a[i][j]=1;
		}
	}
	for(int i=1;i<=m;i++){
		ll x,sum=0,y;char c;
		scanf("%lld%c",&x,&c);
		y=ll(c-'A'+1);
		if(y==1)	sum+=a[x][2];
		if(y==6)	sum+=a[x][5];
		a[x][y]=0;
		if(y==3||y==4)	update(1,1,n,x);
		s[i].pre=sum+query(1,1,n,1,x);
		s[i].suf=sum+query(1,1,n,x,n);
		s[i].bh=i;
	}
	sort(s+1,s+m+1,cmp);
	for(int i=1;i<=m;i++){
		pres[i]=pres[i-1]+s[i].pre;
	}
	for(int i=m+1;i>=1;i--){
		sufs[i]=sufs[i+1]+s[i].suf;
	}
	for(int i=0;i<=m;i++){
		sum=(i*(i-1)/2+(m-i)*(m-i-1)/2)*B+(pres[i]+sufs[i+1])*A;
		ans=min(ans,sum);
	}
	printf("%lld\n",ans);
}
2022/9/29 21:18
加载中...