17.10.7B组总结

17.10.7B组总结

今天的比赛如下所示:

=2

可惜我没AK,(⊙o⊙)…

T1

我自豪地表示我打了正解。
由于这题可以用二分,所以我一言不合用了二分,DP判断时发现仍有时超可能,且答案具有线性,于是我又用了单调队列。
判断过程:

function pd(x:longint):boolean;
var
        i,st,en,j:longint;
        g,d:array[0..50000]of longint;
begin
        fillchar(g,sizeof(g),0);
        fillchar(d,sizeof(d),0);
        st:=1;
        en:=1;
        for i:=1 to n+1 do
        begin
                while (st<=en)and(d[st]<i-x-1) do
                        inc(st);
                g[i]:=g[d[st]]+a[i];
                while (st<=en)and(g[d[en]]>g[i]) do
                        dec(en);
                inc(en);
                d[en]:=i;
        end;
        if g[n+1]>t then
                exit(false);
        exit(true);
end;

T2

第一眼看到这题,我便想到了曾经做过的——锻炼身体(https://jzoj.net/senior/#main/show/1753
于是有了与此题类似的DP想法,设f[i,j,k]表示到了第i个时间段,j行k列的最大移动步数。方程显然。
听说正解用了单调队列,今天是单调队列专题?

uses math;
var
        n,m,x,y,k,i,j,l,ans,xx,yy,tot:longint;
        a:array[0..200,0..200]of longint;
        c:array[0..200,1..3]of longint;
        f:array[0..201,0..200,0..200]of longint;
        fx:array[0..4,1..2]of longint=((0,0),(-1,0),(1,0),(0,-1),(0,1));
        ch:char;
begin
        readln(n,m,x,y,k);
        for i:=1 to n do
        begin
                for j:=1 to m do
                begin
                        read(ch);
                        if ch='.' then
                                a[i,j]:=1;
                end;
                readln;
        end;
        f[1,x,y]:=1;
        for i:=1 to k do
        begin
                readln(c[i,1],c[i,2],c[i,3]);
                for j:=1 to n do
                        for l:=1 to m do
                                if f[i,j,l]<>0 then
                                begin
                                        f[i+1,j,l]:=max(f[i+1,j,l],f[i,j,l]);
                                        xx:=j;
                                        yy:=l;
                                        tot:=0;
                                        while true do
                                        begin
                                                inc(xx,fx[c[i,3],1]);
                                                inc(yy,fx[c[i,3],2]);
                                                inc(tot);
                                                if (xx>0)and(yy>0)and(xx<=n)and(yy<=m)and(a[xx,yy]=1)and(tot-1<=c[i,2]-c[i,1]) then
                                                        f[i+1,xx,yy]:=max(f[i+1,xx,yy],f[i,j,l]+tot)
                                                else
                                                        break;
                                                ans:=max(ans,f[i+1,xx,yy]);
                                        end;
                                end;
        end;
        writeln(ans-1);
end.

T3

比赛唯一没对的题,其实挺简单的,想到思路一码就过。
容易想到,对于两个点,最长边的最小值定在这个图的最小生成树上,于是我们可以删掉无用的边。接着再将这两个点到他们的LCA(最近公共祖先)找出来,答案就在这条路径上。

uses math;
var
        i,n,m,k,gx,gy,op,x,y,tot,j,r:longint;
        a:array[0..30000,1..3] of longint;
        fa,d:array[0..15000] of longint;
        tov,next,last,len:array[0..80000] of longint;
        f:array[0..80000,1..2] of longint;
        g,wer:array[0..15000,0..16] of longint;
procedure kp(l,r:longint);
var
        i,j,mid:longint;
begin
        i:=l;
        j:=r;
        mid:=a[(l+r) div 2,3];
        repeat
                while a[i,3]<mid do inc(i);
                while a[j,3]>mid do dec(j);
                if i<=j then
                begin
                        a[0]:=a[i];
                        a[i]:=a[j];
                        a[j]:=a[0];
                        inc(i);
                        dec(j);
                end;
        until i>j;
        if l<j then kp(l,j);
        if i<r then kp(i,r);
end;
function get(k:longint):longint;
begin
        if fa[k]=0 then
                exit(k);
        fa[k]:=get(fa[k]);
        exit(fa[k]);
end;
procedure insert(x,y,z:longint);
begin
        inc(tot);
        tov[tot]:=y;
        len[tot]:=z;
        next[tot]:=last[x];
        last[x]:=tot;
end;
procedure dg(t,y:longint);
var
        i:longint;
begin
        d[t]:=d[y]+1;
        i:=last[t];
        while i<>0 do
        begin
                if tov[i]<>y then
                begin
                        dg(tov[i],t);
                        f[tov[i],1]:=t;
                        f[tov[i],2]:=len[i];
                end;
                i:=next[i];
        end;
end;
function lca(x,y:longint):longint;
var
        k:longint;
begin
        lca:=-maxlongint;
        while d[x]<d[y] do
        begin
                lca:=max(lca,f[y,2]);
                y:=f[y,1];
        end;
        while d[x]>d[y] do
        begin
                lca:=max(lca,f[x,2]);
                x:=f[x,1];
        end;
        while x<>y do
        begin
                lca:=max(lca,f[y,2]);
                y:=f[y,1];
                lca:=max(lca,f[x,2]);
                x:=f[x,1];
        end;
end;
begin
        readln(n,m,k);
        for i:=1 to m do
                readln(a[i,1],a[i,2],a[i,3]);
        kp(1,m);
        for i:=1 to m do
                if get(a[i,1])<>get(a[i,2]) then
                begin
                        insert(a[i,1],a[i,2],a[i,3]);
                        insert(a[i,2],a[i,1],a[i,3]);
                        gx:=get(a[i,1]);
                        gy:=get(a[i,2]);
                        fa[gx]:=gy;
                end;
        dg(1,0);
        for i:=1 to k do
        begin
                readln(x,y);
                writeln(lca(x,y));
        end;
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值