1445: Pku3245 Sequence Partitioning

来源:互联网 发布:淘宝商城怎么开 编辑:程序博客网 时间:2024/05/21 04:22

1445: Pku3245 Sequence Partitioning

Time Limit: 8 Sec  Memory Limit: 64 MB
Submit: 102  Solved: 59
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

4 6
4 3
3 5
2 5
2 4

Sample Output

9

HINT

An available assignment is the first two pairs are assigned into the first part and the last two pairs are assigned into the second part. Then B1 > A3, B1 > A4, B2 > A3, B2 > A4, max{A1, A2}+max{A3, A4} ≤ 6, and minimum max{B1+B2, B3+B4}=9.

Source

[Submit][Status][Discuss]

对于三类限制条件,逐一分析
对于第一条,转变成,如果有i < j && bi <= aj,那么从i到j这一段的所有物品必须分在同一组
这样将必须合并的合并好,剩下的物品无论怎样划分都不会和第一个限制冲突
题目要求第三类限制尽可能小,那么二分一个答案
定义状态fi:前i个物品在当前二分答案下能够造出的合法方案的∑Mk的最小值
那么有,fi = max{fj + max{Aj+1 ~ Ai}}
由于每个位置i能够转移过来的j一定小于它
并且,对于任意i < j,总有fi <= fj
那么在从左往右扫描的时候,维护一个A单调递减的栈
对于相邻两个元素x,y,从x ~ y-1这一段的转移增加的M的值都是Ay
因为x是最左边的那个,所以用x转移肯定是最优的
这样相邻的两个元素就用一个堆维护转移贡献
对于最左端点,人工特判一下就行了
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<vector>#include<queue>#include<set>#include<map>#include<stack>#include<bitset>#include<ext/pb_ds/priority_queue.hpp>using namespace std; const int maxn = 1E5 + 10;typedef long long LL;const LL INF = 1E15; struct data{    int Num; LL F,G; data(){}    data(int Num,LL F,LL G): Num(Num),F(F),G(G){}    bool operator < (const data &B) const {return F + G > B.F + B.G;}}; int n,cnt,head,tail,q[maxn],A[maxn],B[maxn],R[maxn],Max[maxn];LL m,sum[maxn],f[maxn],g[maxn];bool inq[maxn]; priority_queue <data> Q; void Add(int l,int r){    ++cnt; Max[cnt] = 0;    for (int i = l; i <= r; i++)        sum[cnt] += 1LL * B[i],Max[cnt] = max(Max[cnt],A[i]);} LL Get_top(){    while (!Q.empty())    {        data k = Q.top();        if (!inq[k.Num] || g[k.Num] != k.G) {Q.pop(); continue;}        else return k.F + k.G;    }    return INF + 233LL;} bool Judge(LL now){    int tmp = q[head = tail = 1] = 0;    while (!Q.empty()) Q.pop();    Q.push(data(0,0,0)); inq[0] = 1;    for (int i = 1; i <= cnt; i++)    {        f[i] = INF; g[i] = 0;        while (sum[i] - sum[tmp] > now) ++tmp;        while (head <= tail && q[head] < tmp)            inq[q[head]] = 0,++head;        while (head <= tail && Max[q[tail]] <= Max[i])            inq[q[tail]] = 0,--tail;        if (head <= tail)        {            g[q[tail]] = Max[i]; inq[q[tail]] = 1;            Q.push(data(q[tail],f[q[tail]],g[q[tail]]));        }        f[i] = Get_top(); q[++tail] = i;        f[i] = min(f[i],f[tmp] + 1LL * Max[q[head]]);    }    return f[cnt] <= m;} int getint(){    char ch = getchar(); int ret = 0;    while (ch < '0' || '9' < ch) ch = getchar();    while ('0' <= ch && ch <= '9')        ret = ret * 10 + ch - '0',ch = getchar();    return ret;} int main(){    #ifdef DMC        freopen("DMC.txt","r",stdin);    #endif         cin >> n >> m;    for (int i = 1; i <= n; i++)        Max[i] = A[i] = getint(),B[i] = getint();    for (int i = n - 1; i; i--) Max[i] = max(Max[i],Max[i + 1]);    for (int i = 1; i <= n; i++)    {        int l = i,r = n;        while (r - l > 1)        {            int mid = l + r >> 1;            if (Max[mid] >= B[i]) l = mid;            else r = mid;        }        R[i] = Max[r] >= B[i] ? r : l;    }    int tl = 1,tr = R[1];    for (int i = 2; i <= n; i++)        if (tr < i) {Add(tl,tr); tl = i; tr = R[i];}        else tr = max(tr,R[i]); Add(tl,tr);         for (int i = 1; i <= cnt; i++) sum[i] += sum[i - 1];    LL l,r; l = 0; r = sum[cnt]; Max[0] = ~0U>>1;    while (r - l > 1LL)    {        LL mid = l + r >> 1LL;        if (Judge(mid)) r = mid;        else l = mid;    }    cout << (Judge(l) ? l : r) << endl;    return 0;}

0 0