【NOIP2015模拟11.3】备用钥匙

55 篇文章 0 订阅

T1备用钥匙

Description

JOI社有N名员工,编号从1到N。所有员工的工作时间从时刻0持续到时刻M,时刻0和时刻M的时候,所有员工都必须在公司内。
某天,出于巧合,JOI社的每个员工都要出行恰好一次。员工i(1<=i<=N)在时刻Si离开公司,时刻Ti回到公司。同一时刻不会同时有两名以上的员工离开或回到公司。
JOI社的入口处有一扇巨大的门,员工只能通过这扇门离开或回到公司。门上挂着一把锁,从公司内部可以任意开锁或上锁,但从公司外部只有持有备用钥匙的人才能开锁或者上锁。时刻0时,锁是锁上的。
每个社员在回到公司的时候,都必须能够进入公司。换句话说,对于任意1<=i<=N,要么员工i持有备用钥匙,要么时刻Ti时门是开着的,否则是不被允许的。员工回到公司的时候,或者携带备用钥匙的员工离开公司的时候,可以选择锁门或不锁。没有携带备用钥匙的员工离开公司的时候没有办法锁门。
JOI社的社长决定把备用钥匙交给N个员工中的K个人。为了避免钥匙的丢失,员工之间不允许借用钥匙。此外,JOI社的社长很重视时间效率,因此每个员工在离开或回到公司的时刻以外,不允许开锁或者上锁。
出于安全的考虑,社长希望上锁的时间越长越好。现在他将员工出入公司的信息和准备交给员工的钥匙数量告诉了你,请你求出在能使所有员工回到公司的时候都能进入公司的大门的前提下,上锁的时间最长是多少。

Input

第一行三个空格分隔的整数N,M,K,表示JOI社的员工有N个,工作时间从时刻0到时刻M,备用钥匙有K把。
接下来N行,第i行(1<=i<=N)有两个空格分隔的整数Si,Ti,表示员工i在时刻Si离开公司,时刻Ti回到公司。

Output

输出一行一个整数,表示上锁时间总和的最大值。

Sample Input

4 20 2
3 11
5 15
6 10
12 18

Sample Output

13
【HINT】
JOI社共有4名员工,工作时间为时刻0~时刻M,共有两把备用钥匙。
将钥匙交予员工2和员工4,一天日程如下:
时刻0,锁是关闭状态
时刻3,员工1离开公司。由于员工1没有备用钥匙,无法锁门。
时刻5,员工2离开公司,锁门。
时刻6,员工3离开公司。由于员工3没有备用钥匙,无法锁门。
时刻10,员工3回到公司,不锁门。
时刻11,员工1回到公司,锁门。
时刻12,员工4离开公司,锁门。
时刻15,员工2回到公司,锁门。
时刻18,员工4回到公司,锁门。
直到时刻20为止,锁都保持关闭状态。上锁的时间段为0~3,5~6,11~20,总计13时段,故答案为13。

Data Constraint

对于100%的数据:
1<=N<=2000
1<=M<=10^9
对于任意i,j (1<=i<=N,1<=j<=N,i≠j),Si≠Sj,Si≠Tj,Ti≠Tj

Solution

我说的区间就为这个区间的间隔时间,即答案求的东西。
首先,按照时刻排序,然后可以发现:连续两个人的进出状态需要满足谁有钥匙使得这个区间能否加入到答案里
1、先进后出:不需要钥匙
2、先进后进:后面的有钥匙
3、先出后进:两个人都要钥匙
4、先出后出:前面的人有钥匙
知道这些之后就可以打爆搜了,20分。
观察一下每种状态,发现如果是第一种,可以直接将这个区间加入答案。对于第二种,把区间加入后面那个人的权值。对于第四种,把区间加入前面那个人的权值。
第三种,从进的人向出的人连一条权值为这个区间的边。
问题变成了,选择一个点,就可以获得这个点的权值,如果一个点与这个点的父亲同时被选,可以获得额外权值。目标为使权值最大。
观察一下连边,会发现所有连边最后形成若干个链(自己想为什么)。把这些链的链头和链尾依次连边,边的权值为0,最后就会形成一条大链。如果两个点一开始在不同的链,合成大链后,这两个点即使一个是另一个的父亲,它们同时选,也不可能可以获得额外权值。所以将小链合并的连边权值为0。把一个点也当成一个链连到一起。
如果一个点自己给自己连边,把这个边的权值加入到这个点的权值就行了。不能自己连自己。
解答这个问题,DP。F[i,j]表示前i个点选了j个,并且选第i个的最大值。
f[i][j]=max(max(f[1~i-2][j-1]),f[i-1][j-1]+边权)+点权。
max(f[1~i-2][j-1])可以边做边求,不需要再枚举。
时间复杂度O(nk)。

code

var
    n,m,k,x,y,i,j,ans,anss:longint;
    a:array[1..4100,1..3] of longint;
    b,g:array[0..2100] of longint;
    f:array[0..2100,0..2100] of longint;
    lb:array[0..2100,1..3] of longint;
    bz:array[1..2100] of boolean;
function max(a,b:longint):longint;begin if a>b then exit(a)else exit(b);end;
procedure px(i,j:longint);
var l,r,m:longint;
    t:array[1..3] of longint;
begin
    l:=i;r:=j;m:=a[(i+j)div 2,1];
    repeat
        while a[i,1]<m do inc(i);while a[j,1]>m do dec(j);
        if i<=j then
        begin
            t:=a[i];a[i]:=a[j];a[j]:=t;
            inc(i);dec(j);
        end;
    until i>j;
    if l<j then px(l,j);
    if i<r then px(i,r);
end;
function doit:longint;
var
    i,j:longint;
begin
    j:=a[1,1]+m-a[n*2,1];
    for i:=1 to n*2-1 do
    begin
        if (a[i+1,3]=1) then
        begin
            if a[i,3]=1 then
            begin
                inc(b[a[i,2]],a[i+1,1]-a[i,1]);
            end
            else
            begin
                j:=j+a[i+1,1]-a[i,1];
            end;
        end
        else
        begin
            if a[i,3]=1 then
            begin
                if a[i,2]=a[i+1,2] then
                begin
                    inc(b[a[i,2]],a[i+1,1]-a[i,1]);
                    continue;
                end;
                lb[a[i+1,2],1]:=a[i,2];
                lb[a[i+1,2],2]:=a[i+1,1]-a[i,1];
                lb[a[i,2],3]:=a[i+1,2];
            end
            else
            begin
                inc(b[a[i+1,2]],a[i+1,1]-a[i,1]);
            end;
        end;
    end;
    exit(j);
end;
function dfs(x:longint):longint;
begin
    bz[x]:=true;
    if lb[x,1]<>0 then exit(dfs(lb[x,1]));
    exit(x);
end;
procedure dg(x_,x,j:longint);
begin
    if x=0 then exit;
    if j=1 then f[x,1]:=b[x]
    else f[x,j]:=max(f[x,j],max(g[j],f[x_,j-1]+lb[x_,2])+b[x]);
    ans:=max(ans,f[x,j]+anss);
    g[j]:=max(g[j],f[x_,j-1]);
    dg(x,lb[x,1],j);
end;


begin
    assign(input,'key.in'); reset(input);
    assign(output,'key.out'); rewrite(output);
    read(n,m,k);
    for i:=1 to n do
    begin
        read(x,y);
        a[i*2-1,1]:=x;a[i*2-1,2]:=i;a[i*2-1,3]:=1;
        a[i*2,1]:=y;a[i*2,2]:=i;a[i*2,3]:=2;
    end;
    px(1,n*2);x:=0;
    anss:=doit;
    for i:=1 to n do
    begin
        if (lb[i,3]=0)and(bz[i]=false) then
        begin
            if x=0 then x:=i;
            lb[j,1]:=i;lb[j,2]:=0;
            j:=dfs(i);
        end;
    end;
    for j:=1 to k do
    begin
        dg(0,x,j);
    end;
    writeln(ans);
    close(input);close(output);
end.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值