1445: Pku3245 Sequence Partitioning

19 篇文章 0 订阅
19 篇文章 0 订阅

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值