• [排序][二分][dp]JZOJ 2747 捡金子


    Description

    从前有一个迷宫,迷宫的外形就像一棵带根树,每个结点(除了叶子结点外)恰好有K个儿子。
    一开始你在根结点,根结点的K个儿子分别标记为‘A’, ‘B’, ‘C’….,而结点‘A’的K个儿子结点分别标记为‘AA’,‘AB’,‘AC’……,依此类推。这棵树一共有L层。
    现在你事先知道M个结点中有金子,并且你可以派出N个机器人去收集金子。首先你可以分别指定每一个机器人的目标结点,于是这些机器人就会收集从根结点到其目标结点这条路径上(包括目标结点)所有的金子,但是每个位置的金子只能被收集一次。
    现在你需要制定一个目标的分配方案,使得收集到的金子最多。

    题解

    首先,我们将m个结点从小到大排序
    那么我们要把树造出来,其实只用将这几个用金子的结点连起来就好了
    我们找到2~m的父亲(或爷爷或曾爷爷或曾曾爷爷或曾曾曾爷爷.....)(用!!二分!!实现),存入队列里边
    最后就可以dp了
        我们设f[i][j]为以第i个结点为根,用第j个机器人的收集金子的最大数
        状态转移方程就是 f[x][i]=max(f[x][i],f[x][i-j]+f[y][j])
        (Ps: x为当前结点 i为当前枚举到用第i个机器人 y为他下一辈的结点 j为他下一辈结点用的机器人)
    

    代码

    uses math;
    type strx=string[55];
    var     num,m,k,l,n,x,i,j:longint;
            next,last,first,bz:array[0..50050]of longint;
            a:array[0..50050]of strx;
            f:array[0..50050,0..50]of longint;
            w:string;
    
    procedure insert(i,j:longint);
    begin
            inc(num);
            next[num]:=last[i];
            last[i]:=num;
            first[num]:=j;
    end;
    
    procedure qsort(l,r:longint);
    var     i,j:longint;
            mid,t:strx;
    begin
            if (l>=r) then exit;
            i:=l; j:=r; mid:=a[(l+r) div 2];
            repeat
                    while (a[i]<mid) do inc(i);
                    while (a[j]>mid) 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;
            qsort(l,j);
            qsort(i,r);
    end;
    
    function find(x:strx):longint;
    var     l,r,mid:longint;
    begin
            l:=1; r:=i;
            while (l<r) do
            begin
                    mid:=(l+r)div 2;
                    if (a[mid]<x)then l:=mid+1 else r:=mid;
            end;
            if (a[l]<>x) then exit(0) else exit(l);
    end;
    
    procedure dp(x:longint);
    var     k,y,i,j:longint;
    begin
            k:=last[x];
            while (k<>0) do
            begin
                    y:=first[k];
                    dp(y);
                    for i:=n downto 1 do
                            for j:=1 to i do
                                    f[x,i]:=max(f[x,i],f[y,j]+f[x,i-j]);
                    k:=next[k];
            end;
            for i:=1 to n do f[x,i]:=f[x,i]+bz[x];
    end;
    
    begin
            readln(m,k,l,n);
            for i:=1 to m do readln(a[i]);
            inc(m);
            a[m]:='';
            qsort(1,m);
            x:=1;
            for i:=2 to m do
            begin
                    w:=a[i];
                    delete(w,length(w),1);
                    j:=find(w);
                    while (j=0) do
                    begin
                            delete(w,length(w),1);
                            j:=find(w);
                    end;
                    insert(j,i);
                    bz[i]:=1;
            end;
            dp(1);
            writeln(f[1,n]);
    end.
    
  • 相关阅读:
    作品-系统-[原生开发]新蓝景CRM管理系统
    作品-网站-[二次开发]汇名惠商城
    js声明json数据,打印json数据,遍历json数据,转换json数据为数组
    js 鼠标滚动到某屏时,加载那一屏的数据,仿京东首页楼层异步加载模式
    js转换数据类型为浮点型,并取两位小数点
    php判断是否是微信客户端的浏览器访问
    百度地图API地理位置和坐标转换
    php 对象中连贯执行方法
    php extract 函数的妙用 数组键名为声明为变量,键值赋值为变量内容
    php 获取远程图片保存到本地
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8412245.html
Copyright © 2020-2023  润新知