题目太蛋疼。。
首先有一个N^2LIMIT的最最暴力的DP。囧
然后可以换个DP的东西,二分答案,然后DP验证是否可行。(f[n]<=LIMIT)
对于第一个条件,其实可以与处理出来最小的必须在一起的块。然后合并起来。然后第一个条件就没了。
然后就要考虑第二个条件了。
还是二分答案,DP验证 。但是N^2的暴力DP肯定要TLE的。
考虑优化一下dp.
转移是:
f[i]=Min{f[j]+MaxA(j+1,i)} sumb(j+1,i)≤X (x是当前二分的答案)
然后这玩意儿竟然可以优化。
MaxA(j+1,i)是随j变大单调不增的。
然后考虑以A为关键字建一个单调递减的栈。
然后用线段树维护f[j]+MaxA(j+1,i) 整个的值
但是修改的只是MaxA(j+1,i)
MaxA(j+1,i)是成段变化的,每次加上一个差值就可以了。
但是f[j]+MaxA(j+1,i) 是不单调的。所以要在线段树里面询问最小值
然后修改一段区间是logN的 ,每个点最多单独更新一次。每次DP是NlogN的。
下面是错误的代码。。。(为啥还放上来 。。)
#include <cstdio>
#include <algorithm>
#define per(i,r,l) for (int i=r;i>=l;--i)
#define rep(i,l,r) for (int i=l;i<=r;++i)
typedef unsigned int UI;
bool upmax(int &a,int b){return a<b?a=b,1:0;}
bool upmax(UI &a,UI b){return a<b?a=b,1:0;}
UI Max(UI a,UI b){return a<b?b:a;}
const int MAX_N=50050;
UI n,lim;
UI a[MAX_N],b[MAX_N];
UI sum[MAX_N];
void New(){
static UI max[MAX_N];
per(i,n,1) max[n-i+1]=Max(max[n-i],a[i]);
static int L[MAX_N],R[MAX_N],top=0;
bool fir=true;int r=0;
rep(i,1,n){
upmax(r,n-(std::lower_bound(max,max+n-i+1,b[i])-max)+1);
if (fir) L[++top]=i,fir=0;
if (i==r) R[top]=i,fir=1;
}
n=top;
rep(i,1,top){
UI s=0,mx=0;
rep(j,L[i],R[i]) upmax(mx,a[j]),s+=b[j];
a[i]=mx,b[i]=s;
sum[i]=sum[i-1]+b[i];
}
}
int getp(UI *a,int l,int r,int v){
if (v<a[l]) return l;
while (r-l>1){
int mid=l+r>>1;
if (v>a[mid]) r=mid;
else l=mid;
}
return r;
}
bool check(UI x){
static UI f[MAX_N],que1[MAX_N],que2[MAX_N];
int h1=0,t2=0,h2=0;
que2[t2]=0;f[0]=0;
rep(i,1,n){
while(0<h1&&a[que1[h1]]<=a[i]) h1--;
que1[++h1]=i;
while(t2<h2&&((sum[i]-sum[que2[t2]])>x)) t2++;
f[i]=f[que2[t2]]+a[getp(que1,1,h1,que2[h2])];
//printf("%d\n",f[i]);
while(t2<h2&&( f[que2[h2]]+a[getp(que1,1,h1,que2[h2])]
>f[i] + a[getp(que1,1,h1,i)])) h2--;
que2[++h2]=i;
}
return f[n]<=lim;
}
void Solve(){
UI l=0,r=1;
rep(i,1,n) upmax(l,b[i]-1),r+=b[i];
while (r-l>1){
UI mid=l+r>>1;
if (check(mid)) r=mid;
else l=mid;
}
printf("%d\n",r);
}
int main(){
freopen("partition.in","r",stdin);
freopen("partition.out","w",stdout);
scanf("%u%u",&n,&lim);
rep(i,1,n) scanf("%u%u",&a[i],&b[i]);
New();
//rep(i,1,n) printf("%d %d\n",a[i],b[i]);
//check(9);
Solve();
}