[DP][二分]JZOJ 3463 军训

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

分析

由于求max-min问题,发现满足二分性以后,可以考虑二分

然后我们想到DP判断

fi为到i为止(不包括i)的最小欠扁值之和

然后方程容易得到:

f[i]=∑min(f[j]+max(h[j]..h[i]))

但是枚举j显然不太现实,O(n^2)的时间复杂度

然后注意到max(f[j]..f[i])是满足单调性的(单调下降或不变)

那么我们设nexti为从i往后第一个满足hnext[i]>hi的位置

那么显然若i≤j<nexti,则max(h[i]..h[j])不变

那么我们可以直接跳过j,跳到nexti即可

时间复杂度为O(knlogn)k为常数(不会算next的时间复杂度,因为数据是可以卡掉的,如果h满足单调上升就可以卡住next,使k退化为n,但是显然没有卡【滑稽】)

#include <iostream>
#include <cstdio>
#include <memory.h>
#define rep(i,a,b) for (i=a;i<=b;i++)
const int N=20002;
using namespace std;
int next[N],nstk[N];
long long sumofg[N],stk[N];
int n;
long long limit;
int g[N],h[N];

int Get_Right(int x,long long lmt) {
    int l=x,r=n,mid;
    while (l<r) {
        mid=l+r>>1;
        if (sumofg[mid]-sumofg[x-1]>=lmt) r=mid;
        else l=mid+1;
    }
    return l;
}

bool Judge(long long lmt) {
    int i;
    long long f[N];
    memset(f,0xf,sizeof f);
    f[1]=0;
    rep(i,1,n) {
        int j=Get_Right(i,lmt),k;
        long long mx;
        if (sumofg[j]-sumofg[i-1]>lmt) j--;
        k=i;mx=h[i];
        while (k<=j) {
            f[k]=min(f[k],f[i]+mx);
            mx=h[k];
            k=next[k];
        }
        f[j+1]=min(f[j+1],f[i]+mx);
    }
    return f[n+1]<=limit;
}

int main() {
    int i,top=1;
    scanf("%d%lld",&n,&limit);
    rep(i,1,n) {
        scanf("%d%d",&h[i],&g[i]);
        sumofg[i]=sumofg[i-1]+g[i];
    }
    stk[top]=2147483647;
    nstk[top]=n+1;
    for (i=n;i;i--) {
        while (h[i]>=stk[top]) top--;
        next[i]=nstk[top];
        top++;
        stk[top]=h[i];
        nstk[top]=i;
    }
    long long l=1,r=sumofg[n],mid,ans=sumofg[n];
    while (l<r) {
        mid=l+r>>1;
        if (Judge(mid)) {
            ans=min(ans,mid);
            r=mid;
        }
        else l=mid+1;
    }
    printf("%lld",ans);
}

原文地址:https://www.cnblogs.com/mastervan/p/9387510.html

时间: 2024-08-02 07:37:46

[DP][二分]JZOJ 3463 军训的相关文章

[DP][二分]JZOJ 3467 最长上升子序列

Description 维护一个序列,使它可以进行下面两种操作: 1.在末尾添加一个数字x 2.将整个序列变成第x次操作后的样子 在每次操作后,输出当前序列的最长上升子序列的长度 序列初始时为空 Input 输入文件lis.in的第一行有一个正整数n,表示操作个数.接下来n行每行有两个整数op,x.如果op为0,则表示添加x这个数字:如果op为1,则表示回到第x次操作之后. Output 对于每次操作,在输出文件lis.out中输出一个答案,表示当前最长上升子序列的长度 Sample Input

POJ-2533最长上升子序列(DP+二分)(优化版)

Longest Ordered Subsequence Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 41944   Accepted: 18453 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ...

hdu3586 树形dp+二分求解

http://acm.hdu.edu.cn/showproblem.php?pid=3586 Problem Description In the battlefield , an effective way to defeat enemies is to break their communication system. The information department told you that there are n enemy soldiers and their network w

HDU 3433 (DP + 二分) A Task Process

题意: 有n个员工,每个员工完成一件A任务和一件B任务的时间给出,问要完成x件A任务y件B任务所需的最短时间是多少 思路: DP + 二分我也是第一次见到,这个我只能说太难想了,根本想不到. dp[i][j]表示在t时间内前i个人完成j件A任务后所能完成B任务的最大数量. 代码中还有一些注释. 1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 using

[数位dp+二分] fzu 1074 Nancy&#39;s Birthday

题意:给m,n,问含有m个0的第k个数,是几位数,并且最高位是多少. 思路:和普通数位dp一样,加上个二分. 然后就是注意一下,极限值测试下能否算出来,这题极限值很大! 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #

poj3208 Apocalypse Someday 数位dp+二分 求第K(K &lt;= 5*107)个有连续3个6的数。

/** 题目:poj3208 Apocalypse Someday 链接:http://poj.org/problem?id=3208 题意:求第K(K <= 5*107)个有连续3个6的数. 思路:数位dp+二分. dp[i][j]表示长度为i,前缀状态为j时含有的个数. j=0表示含有前导0: j=1表示前缀连续1个6 j=2表示前缀连续2个6 j=3表示前缀连续3个6 j=4表示前缀不是6: */ //#include<bits/stdc++.h> #include<cstr

hdu 1025 Constructing Roads In JGShining’s Kingdom 【dp+二分】

题目链接:http://acm.acmcoder.com/showproblem.php?pid=1025 题意:本求最长公共子序列,但数据太多.转化为求最长不下降子序列.太NB了.复杂度n*log(n). 解法:dp+二分 代码: #include <stdio.h> #include <string.h> #include <vector> #include <string> #include <algorithm> #include <

hdu2993之斜率dp+二分查找

MAX Average Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5825    Accepted Submission(s): 1446 Problem Description Consider a simple sequence which only contains positive integers as

hdu 1025 Constructing Roads In JGShining&#39;s Kingdom(DP + 二分)

此博客为转发 Constructing Roads In JGShining's Kingdom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description JGShining's kingdom consists of 2n(n is no more than 500,000) small cities which are located in t