Time Limits: 2000 ms Memory Limits: 262144 KB Detailed Limits
Description
HYSBZ 開學了!今年HYSBZ 有n 個男生來上學,學號爲1…n,每個學生都必須參加軍訓。在這種比較墮落的學校裏,每個男生都會有Gi 個女朋友,而且每個人都會有一個欠扁值Hi。學校爲了保證軍訓時教官不會因爲學生們都是人生贏家或者是太欠扁而發生打架事故,所以要把學生們分班,並做出瞭如下要求:
1.分班必須按照學號順序來,即不能在一個班上出現學號不連續的情況。
2.每個學生必須要被分到某個班上。
3.每個班的欠扁值定義爲該班中欠扁值最高的那名同學的欠扁值。所有班的欠扁值之和不得超過Limit。
4.每個班的女友指數定義爲該班中所有同學的女友數量之和。在滿足條件1、2、3 的情況下,分班應使得女友指數最高的那個班的女友指數最小。
請你幫HYSBZ 的教務處完成分班工作,並輸出女友指數最高的班級的女友指數。
輸入數據保證題目有解。
Input
第一行僅2 個正整數n, Limit,分別爲學生數量和欠扁值之和的上限。
接下來n 行每行2 個正整數Hi,Gi,分別爲學號爲i 的學生的欠扁值和女友數。
Output
僅1 個正整數,表示滿足分班的條件下女友指數最高的班級的女友指數。
Sample Input
4 6
4 3
3 5
2 2
2 4
Sample Output
8
【樣例解釋】
分班按照(1,2),(3,4)進行,這時班級欠扁值之和爲4+2=6<=Limit,而女友指數最高的班級爲(1,2),爲8。容易看出該分班方案可得到最佳答案。
Data Constraint
對於20%的數據:n,Limit<=100
對於40%的數據:n<=1000
對於100%的數據:1<=n,Gi<=20000,1<=Hi,Limit<=10^7
解法:二分+單調隊列
我也不太會,就粘了下代碼
#include<iostream>
#include<cstring>
using namespace std;
long long b[20005],f[20005],lim,mid,w;
int n,k,t,x,tj=1,q[20005],next[20005],a[20005],c[20005];
inline int work(int x) {
int l=x,r=n;
while(l<r) {
int mid1=(l+r)>>1;
if(b[mid1]-b[x-1]>=mid) r=mid1;
else l=mid1+1;
}
return l;
}
inline bool check() {
memset(f,127,sizeof(f)); f[1]=0;
for(int i=1;i<=n;i++) {
int x=i,w=q[x],k=work(i);
if(b[k]-b[i-1]>mid) k--;
while(x<=k) {
f[x]=min(f[x],f[i]+w);
w=q[x]; x=next[x];
}
f[k+1]=min(f[k+1],f[i]+w);
}
if(f[n+1]>lim) return 0;
return 1;
}
int main() {
cin>>n>>lim;
for(int i=1;i<=n;i++) {
cin>>q[i]>>x;
b[i]=b[i-1]+x;
}
a[1]=n+1; c[1]=2147483647;
for(int i=n;i;i--) {
while(q[i]>=c[tj]) tj--;
next[i]=a[tj];
c[++tj]=q[i];
a[tj]=i;
}
int l=1,r=b[n];
while(l<r) {
mid=(l+r)>>1;
if(check()) r=mid;
else l=mid+1;
}
cout<<l;
return 0;
}