二分+线段树 [USACO17JAN]Cow Dance Show S(洛谷 P3611)

[USACO17JAN]Cow Dance Show S

题目描述

After several months of rehearsal, the cows are just about ready to put on their annual dance performance; this year they are performing the famous bovine ballet “Cowpelia”.

The only aspect of the show that remains to be determined is the size of the stage. A stage of size KK can support KK cows dancing simultaneously. The NN cows in the herd (1 \leq N \leq 10,0001≤N≤10,000) are conveniently numbered 1 \ldots N1…N in the order in which they must appear in the dance. Each cow ii plans to dance for a specific duration of time d(i)d(i). Initially, cows 1 \ldots K1…K appear on stage and start dancing. When the first of these cows completes her part, she leaves the stage and cow K+1K+1 immediately starts dancing, and so on, so there are always KK cows dancing (until the end of the show, when we start to run out of cows). The show ends when the last cow completes her dancing part, at time TT.

Clearly, the larger the value of KK, the smaller the value of TT. Since the show cannot last too long, you are given as input an upper bound T_{max}T
max

specifying the largest possible value of TT. Subject to this constraint, please determine the smallest possible value of KK.

经过几个月的排练,奶牛们基本准备好展出她们的年度舞蹈表演。今年她们要表演的是著名的奶牛芭蕾——“cowpelia”。

表演唯一有待决定的是舞台的尺寸。一个大小为K的舞台可以支持K头牛同时在舞台上跳舞。在牛群中的N头牛(1<=N<=10,000)按照她们必须出现在舞蹈中的顺序方便地编号为1…N。第i头牛计划跳d[i]的特定持续时间。一开始,第1…K头牛出现在舞台上并开始跳舞。当这些牛中的某一头牛首先完成了她的部分,她会马上离开舞台并且第K+1头牛会出现在舞台上并开始跳舞。所以,舞台上总有K头奶牛在跳舞(直到表演的尾声,奶牛不够的时候)。当最后一头奶牛完成了她的舞蹈部分,表演结束,共花了T个单位时间。

显然,K的值越大,T就越小。由于表演不能拖太长,你得知了指定T的最大可能值的上限T-max。请根据这个约束,确定K的最小值。

输入格式

The first line of input contains NN and T_{max}T
max

, where T_{max}T
max

is an integer of value at most 1 million.

The next NN lines give the durations d(1) \ldots d(N)d(1)…d(N) of the dancing parts for cows 1 \ldots N1…N. Each d(i)d(i) value is an integer in the range 1 \ldots 100,0001…100,000.

It is guaranteed that if K=NK=N, the show will finish in time.

第一行包括N和T-max两个整数(T-max<=1,000,000)。

接下来的N行给出了第1…n头牛跳舞的持续时间d[1]…d[n]。第i行包括一个整数d[i],1<=d[i]<=100,000.

保证K=N时表演会按时完成。

输出格式

Print out the smallest possible value of KK such that the dance performance will take no more than T_{max}T
max

units of time.

输出在表演时间不大于T-max时的K的最小可能值。


二分 K 很明显,就是这个线段树写起来比较麻烦;

首先知道是维护区间最大,最小值,每次取区间最小值,然后减去区间最小值,当到达最后一个的时候,直接加上区间最大值,因为这个时候没有奶牛入队了;

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=10100;
const int M=2000100;
const int mod=1e9;
int n,m,d[N];
struct Node{
	int l,r,mmin,mmax,pos,f;
}tr[N*4];
void pp(int k){
	if(tr[ls].mmin<=tr[rs].mmin) tr[k].mmin=tr[ls].mmin,tr[k].pos=tr[ls].pos;
	else tr[k].mmin=tr[rs].mmin,tr[k].pos=tr[rs].pos;
	tr[k].mmax=max(tr[ls].mmax,tr[rs].mmax);
}
void pd(int k){
	if(tr[k].f){
		tr[ls].mmax-=tr[k].f,tr[rs].mmax-=tr[k].f;
		tr[ls].mmin-=tr[k].f,tr[rs].mmin-=tr[k].f;
		tr[ls].f+=tr[k].f,tr[rs].f+=tr[k].f;
	}
	tr[k].f=0;
}
void build(int l,int r,int k){
	tr[k].l=l,tr[k].r=r,tr[k].f=0;
	if(l==r){
		tr[k].mmin=d[l],tr[k].mmax=d[l],tr[k].pos=l;
		return;
	}
	int d=(l+r)>>1;
	build(l,d,ls);
	build(d+1,r,rs);
	pp(k);
}
void add(int pos,int w,int k){
	if(tr[k].l==tr[k].r){
		tr[k].mmin=w,tr[k].mmax=w;
		return;
	}
	pd(k);
	int d=(tr[k].l+tr[k].r)>>1;
	if(pos<=d) add(pos,w,ls);
	else add(pos,w,rs);
	pp(k);	
}
void update(int w,int k){
	tr[k].mmax-=w,tr[k].mmin-=w;
	tr[k].f+=w;
} 
bool judge(int p){
	LL ans=0;
	build(1,p,1);
	if(p==n) ans+=tr[1].mmax;
	else ans+=tr[1].mmin;
	for(int i=p+1;i<=n;i++){
		update(tr[1].mmin,1);
		add(tr[1].pos,d[i],1);
		if(i==n) ans+=tr[1].mmax;
		else ans+=tr[1].mmin;
	}
	if(ans<=1ll*m) return true;
	return false;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&d[i]);
	int l=1,r=n,ans=0;
	while(l<=r){
		int d=(l+r)>>1;
		if(judge(d)){
			ans=d;
			r=d-1;
		}
		else l=d+1;
	}
	printf("%d\n",ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值