HYSBZ 开学了!今年HYSBZ 有n 个男生来上学,学号为1…n,每个学生都必须参加军训。在这种比较堕落的学校里,每个男生都会有Gi 个女朋友,而且每个人都会有一个欠扁值Hi。学校为了保证军训时教官不会因为学生们都是人生赢家或者是太欠扁而发生打架事故,所以要把学生们分班,并做出了如下要求:
1.分班必须按照学号顺序来,即不能在一个班上出现学号不连续的情况。
2.每个学生必须要被分到某个班上。
3.每个班的欠扁值定义为该班中欠扁值最高的那名同学的欠扁值。所有班的欠扁值之和不得超过Limit。
4.每个班的女友指数定义为该班中所有同学的女友数量之和。在满足条件1、2、3 的情况下,分班应使得女友指数最高的那个班的女友指数最小。
请你帮HYSBZ 的教务处完成分班工作,并输出女友指数最高的班级的女友指数。
输入数据保证题目有解。
一看到这题,想:哈哈哈,又是一道最大的最小,随便搞搞~~
(10M之后…)冥思苦想ing…
这题用二分套线段树来搞(其实我觉得有一种更好的代替法),
先来看看 O(log2(4∗108)∗n2) 的方法,
二分一个t,表示所有组最多的女友指数,
设 fi 表示当前组以i为结尾的最小欠扁值,
Dp式:
#include
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=20500,M=15,maxlongint=2147483640;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans;
int h[N],g[N],H[N],G[N];
int f[N];
int za[N];
int b[N*4],ad[N*4],la[N*4],bs[N*4];
int min(int a,int b){return a>b?b:a;}
int max(int a,int b){return aint l,int r,int e)
{
if(!la[e])return;
b[e]=bs[e];
ad[e]=la[e];
if(l!=r)la[e*2]=max(la[e*2],la[e]),la[e*2+1]=max(la[2*e+1],la[e]);
la[e]=0;
}
void HB(int l,int r,int e)
{
if(l==r)return;
bs[e]=min(bs[e*2],bs[e*2+1]);
if(b[e*2]+ad[e*2]>b[e*2+1]+ad[e*2+1])b[e]=b[e*2+1],ad[e]=ad[e*2+1];
else b[e]=b[e*2],ad[e]=ad[e*2];
}
void modify(int l,int r,int e,int l1,int r1,int l2)
{
if(rreturn;
if(la[e])doit(l,r,e);
if(l==l1&&r==r1)
{
la[e]=l2;doit(l,r,e);
return;
}
int t=(l+r)/2;
if(r1<=t)modify(l,t,e*2,l1,r1,l2),doit(l,r,e*2+1);
else if(t*2),modify(t+1,r,e*2+1,l1,r1,l2);
else
{
modify(l,t,e*2,l1,t,l2);
modify(t+1,r,e*2+1,t+1,r1,l2);
}
HB(l,r,e);
}
int find(int l,int r,int e,int l1,int r1)
{
if(la[e])doit(l,r,e);
if(l==l1&&r==r1)return b[e]+ad[e];
int t=(l+r)/2,ans=maxlongint;
if(r1<=t)ans=find(l,t,e*2,l1,r1),doit(l,r,e*2+1);
else if(t*2),ans=find(t+1,r,e*2+1,l1,r1);
else
{
ans=min(find(l,t,e*2,l1,t),find(t+1,r,e*2+1,t+1,r1));
}
HB(l,r,e);
return ans;
}
void change(int l,int r,int e,int l1,int l2)
{
if(la[e])doit(l,r,e);
if(l==r&&l==l1)
{
b[e]=bs[e]=l2;ad[e]=0;
return;
}
int t=(l+r)/2;
if(l1<=t)change(l,t,e*2,l1,l2),doit(l,r,e*2+1);
else if(t*2),change(t+1,r,e*2+1,l1,l2);
HB(l,r,e);
}
bool OK(int t)
{
memset(b,0,sizeof(b));
memset(ad,0,sizeof(ad));
memset(la,0,sizeof(la));
memset(bs,0,sizeof(bs));
int w=0,q=1;
fo(i,1,n)
{
w+=g[i];while(w>t)w-=g[q++];
G[i]=q;
}
modify(0,n,1,0,0,h[1]);
f[1]=h[1];change(0,n,1,1,f[1]);
fo(i,2,n)
{
modify(0,n,1,max(H[i],G[i]-1),i-1,h[i]);
f[i]=find(0,n,1,G[i]-1,i-1);
change(0,n,1,i,f[i]);
}
if(f[n]>m)return 0;
return 1;
}
int main()
{
int q,w,l,r;
read(n),read(m);
l=r=0;
fo(i,1,n)read(h[i]),r+=read(g[i]),l=max(l,g[i]);
za[0]=0;
fo(i,1,n)
{
while(za[0]&&h[za[za[0]]]0]--;
H[i]=za[za[0]];za[++za[0]]=i;
}
while(lint t=(l+r)/2;
if(OK(t))r=t;else l=t+1;
}
printf("%d\n",l);
return 0;
}