记录编号 293068 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 1363.水站 最终得分 100
用户昵称 kito 是否通过 通过
代码语言 C++ 运行时间 0.118 s
提交时间 2016-08-09 17:48:46 内存使用 0.69 MiB
显示代码纯文本
#include<cstdio>
using namespace std;
#define fcl fclose(stdin);	fclose(stdout);	return 0
int n;
int W[15010]={0},L[15010]={0},P[15010]={0};
int Nw[15010]={0},Place[15010]={0}; 

int GetPlace(int i){
	if(i==13){}
	int l=0,r=i-1,mid;
	while(l<=r){
		mid=(l+r)>>1;
		if(Nw[i]-Nw[mid]>L[i])	l=mid+1;
		else r=mid-1;
	}
	return l+1;
}

int kito[15010]={0};
void Archer1(int a,int k){
	for(int i=a;i<=n;i+=(i&(-i))){
		kito[i]+=k;
	}
}
int Saber1(int a){
	int tot=0;
	for(int i=a;i>=1;i-=(i&(-i))){
		tot+=kito[i];
	}
	return tot;
}

int alice[15010]={0};
void Archer2(int a,int k){
	for(int i=a;i<=n;i+=(i&(-i))){
		alice[i]+=k;
	}
}
int Saber2(int a){
	int tot=0;
	for(int i=a;i>=1;i-=(i&(-i))){
		tot+=alice[i];
	}
	return -tot;
}

int main(){
	freopen("station.in","r",stdin);
	freopen("station.out","w",stdout);
	
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d%d%d",&W[i],&L[i],&P[i]);
		Nw[i]=Nw[i-1]+W[i];//求水量的前缀和 
	}
	int x;
	/*
		如果某一个水站能从上面的水站获得水,证明上面的水站一定减压(但不一定是手动减压)
		为了使n减压,我是为了让n获得水,也就是说,我最高的减压水站的水要能进入n水站。也就是说,
	从最高的减压水站开始到n都要减压。
		为了节省资金,应该是让水站尽可能自动开闸。
		如果i是最高的减压水站,那么下面的每个水站获得的水量都是固定且已知的。
		j水站上面开闸的水站越多,就越可能不花钱开闸。
		我们可以二分求得,第j水站必须花钱开闸时,最高的水站的最高位置。
		这就是GetPlace函数。 
	*/ 
	for(int i=1;i<=n;++i){
		x=GetPlace(i);//求得第i个水站必须手动减压时,最高的开始位置。 
		Place[i]=x;
		Archer1(x,P[i]);//利用树状数组。 
		Archer2(i+1,P[i]);// 从x到i+1需要花i的钱手动开闸。 
	}
	int Minn=0x7fffffff,a,Ans;
	for(int i=1;i<=n;++i){
		a=Saber1(i)+Saber2(i);
		if(a<Minn){
			Minn=a;
			Ans=i;
		}
	}
	printf("%d\n",Minn);
	for(int i=Ans;i<=n;++i){
		if(Place[i]<=Ans)	printf("%d ",i);//如果必须花钱的位置的起始位置在Ans之外,就要花钱。 
	}
	fcl;
}