【2019夏•紀中游記】

Day1

$ \Large\texttt{預估/實際分數:200/200}$html

T1

題目

題目描述
Wexley最近發現了一個古老的屏幕遊戲。遊戲的屏幕被劃分紅n列。
在屏幕的底端,有一個寬爲m列的籃子(m<n)。
在遊戲過程當中,Wexley能左右移動這個籃子,
         Wexley的操做很犀利,移動是瞬間完成的,可是籃子必須始終都在屏幕中。 蘋果從屏幕的頂端落下,每一個蘋果從n列中的某一列頂端掉落,
垂直掉落到屏幕的底端。每一個蘋果老是在上一個蘋果掉落到底端的時候開始掉落。
Wexley想要經過移動籃子來接住全部的蘋果。起先,籃子在屏幕的最左端。
         求出Wexley要接住全部的蘋果所需移動的最短距離。
輸入
第一行,兩個整數n、m,如題所述
第二行,一個整數k,表示掉落的蘋果總數
接下來k行,每行一個整數Ai,表示每一個蘋果掉落的位置
輸出
一行一個整數,表示所需移動最短距離
樣例輸入
Sample Input1:
5 1
3
1
5
3

Sample Input2:
5 2
3
1
5
3
樣例輸出
Sample Output1:
6

Sample Output2:
4

思路

本題的算法是模擬。node

假設籃子的左邊的位置是\(x\), 蘋果的位置是\(y\)算法

若是蘋果在籃子右邊就只要走\(y - x - (m - 1)\)步,
若是蘋果在籃子左邊就要走\(x - y\)步。數組

籃子的位置再隨着移動就行了。學習

代碼

for (int i = 1; i <= k; i++) 
{
    scanf ("%d", &y);
    if (y >= x && y <= x + m - 1) continue;
    if (x < y)
    {
        ans += y - x - (m - 1);
        x = y - m + 1; 
    }
    else
    {
        ans += x - y;
        x = y; 
    }
}

T2

題目

題目描述
Leo是一個快樂的火星人,老是能和地球上的OIers玩得很high。
         2012到了,Leo又被召回火星了,在火星上沒人陪他玩了,
可是他有好多好多積木,因而他開始搭積木玩。
       火星人能製造n種積木,積木能無限供應。每種積木都是長方體,第i種積木的長、寬、高分別爲li、wi、hi。
積木能夠旋轉,使得長寬高任意變換。Leo想要用這些積木搭一個最高的塔。問題是,
若是要把一個積木放在另外一個積木上面,
必須保證上面積木的長和寬都嚴格小於下面積木的長和寬。這意味着,
即便兩塊長寬相同的積木也不能堆起來。
       火星上沒有電腦,好心的你決定幫助Leo求出最高的塔的高度。

【提示】
每種積木均可以拆分紅高度分別爲li、wi、hi的三種積木,另兩邊做爲長和寬,保證長>=寬。
輸入
第一行,一個整數n,表示積木的種數
接下來n行,每行3個整數li,wi,hi,表示積木的長寬高
輸出
一行一個整數,表示塔高的最大值
樣例輸入
Sample Input1:
1
10 20 30


Sample Input2:
2
6 8 10
5 5 5



Sample Input3:
5
31 41 59
26 53 58
97 93 23
84 62 64
33 83 27
樣例輸出
Sample Output1:
40


Sample Output2:
21


Sample Output3:
342

思路

本題的算法是動態規劃。優化

首先,由於它的長、寬、高能夠任意位置,因此把每個合理(即長$\geq $寬) 記錄下來,每個積木就會有\(3\)種方案,排個序。spa

\(F_i\)表示第\(i\)個積木放了的話,塔的高度,那麼動態轉移方程就能推出來了code

代碼

bool cmp(node a, node b)  //排寬
{
    return a.w > b.w;
}
bool cmp2(node a, node b) //排長
{
    return a.h > b.h;
}
for (int i = 1; i <= n; i++)     //記錄方案與讀入
{
    int l, w, h;
    scanf ("%d%d%d", &l, &w, &h);
    if (w <= h)a[++m].l = l, a[m].w = w, a[m].h = h;
    if (h <= w)a[++m].l = l, a[m].w = h, a[m].h = w;
    if (l <= w)a[++m].l = h, a[m].w = l, a[m].h = w;
    if (w <= l)a[++m].l = h, a[m].w = w, a[m].h = l;
    if (l <= h)a[++m].l = w, a[m].w = l, a[m].h = h;
    if (h <= l)a[++m].l = w, a[m].w = h, a[m].h = l;
}
sort(a + 1, a + 1 + m, cmp);
for (int i = 1, begin = 1; i <= m; i++)  //排序(方法可能很獨特...)
{
    if(a[i].w != a[i + 1].w)
    {
        sort(a + begin, a + 1 + i, cmp2);
        begin = i + 1;
    }
}
a[0].h = 2147483646;                   //DP
a[0].w = 2147483646;
f[1] = a[1].l;
for (int i = 2; i <= m; i++)
{
    for (int j = i - 1; j >= 0; j--)
    {
        if (!(a[i].h < a[j].h && a[i].w < a[j].w)) continue;
        f[i] = max(f[i], f[j] + a[i].l);
    }
}
for (int i = 2; i <= m; i++)
    ans = max(ans, f[i]);
printf("%lld", ans);

T3

題目

題目描述
Treeland是一個有n個城市組成的國家,其中一些城市之間有單向邊連通。在這個國家中一共有n-1條路。
咱們知道,若是咱們不考慮路的方向,那麼我能夠從任意城市到達任意城市。
      最近,Treeland的總理Candy爲了發展經濟,想要從這n個城市中選擇一個做爲Treeland的首都,
首都必需要能到達其餘任意城市,這使得有些道路必須反向,
付出的代價即須要反向的道路條數。
      Candy想要選擇一個城市做爲首都,使得付出的代價最小。
可能有多個城市知足條件,按編號從小到大輸出。
輸入
第一行,一個整數n,表示城市個數
接下來n-1行,每行兩個整數x、y,表示城市x到城市y之間有一條單向路徑
輸出
第一行,一個整數k,花費的最小代價。
第二行若干個整數,中間用空格隔開,表示知足條件的城市編號。行末沒有多餘的空格。
樣例輸入
Sample Input1:
3
2 1
2 3

Sample Input2:
4
1 4
2 4
3 4
樣例輸出
Sample Output1:
0
2

Sample Output2:
2
1 2 3

思路

本題的算法是搜索(樹形,有點像樹形DP)。htm

可惡啊,\(\texttt{C++}\)作這題就錯了(\(\texttt{90}\)分)緣由是棧溢出\(\texttt{Pascal}\)就對了TAT。。。blog

存樹時仍是按雙向邊來存,若是是出度那就是\(1\),若是是入度那就是\(0\)(代碼中有存儲方式)。

而後呢???

咱們用一個數組\(sx\)(名字是瞎取的)來存下以\(x\)爲根節點的,有多少個入度,這也將會是最終的答案。

咱們就是來求這個\(sx\)的。

怎麼求呢?

咱們能夠從根搜到葉子,記錄每個節點的入度(\(\texttt{for}\)一遍兒子節點),再退回給本身的父親。

你覺得這就結束了???

這只是求出了根節點的值!

怎麼求兒子呢?

這裏有一條性質:

當前節點\(x\)的一個兒子\(y\),若是是\(x\)指向\(y\),那\(sx_y=sx_x+1\)。不然\(sx_y=sx_x-1\)

你們能夠根據下圖模擬一下。

圖1

先拿節點\(1\)來講咱們從求根節點的時候就已經知道了\(sx_1=1\)

而後是節點\(2\),根據上面說的能夠知道\(sx_2=sx_1-1\)也就是\(sx_2=1-1=0\)確實沒錯。

而後是節點\(3\),根據上面說的能夠知道\(sx_3=sx_1+1\)也就是\(sx_3=1+1=2\)確實也沒錯(\(2\Rightarrow 1,1\Rightarrow 3\))。

。。。

代碼

**聲明:下面的prework實際上是某大佬和某教授讓我加的(是寫\(\texttt{C++}\)的時候加的,結果這個優化毫無*用)**

var
    minn, end1, x, y, i, j, n, tot : longint;
    head, sx, fa : array[1..200010]of longint;
    next, to1, qz : array[1..400010]of longint;

procedure add1(x, y, op : longint);
begin
    inc(tot);
    to1[tot] := y; qz[tot] := op; next[tot] := head[x]; head[x] := tot;
end;

procedure prework(x : longint);
var
    y, i : longint;
begin
    i := head[x];
    while(i >= 1) do
    begin
        y := to1[i];
        if(fa[x] = y)then
        begin
            i := next[i];
            continue
        end;
        fa[y] := x;
        prework(y);
        i := next[i];
    end;
    exit();
end;

procedure init(x : longint);
var
    i, y : longint;
begin
    i := head[x];
    while(i > 0) do
    begin
        y := to1[i];
        if(fa[x] = y)then
        begin
            i := next[i];
            continue
        end;
        if(y = 0) then break;
        init(y);
        inc(sx[x], sx[y]);
        if(qz[i] = 0)then
            inc(sx[x])
        else
            inc(sx[y]);
        i := next[i];
    end;
end;
procedure repeat1(x : longint);
var
    i, y : longint;
begin
    i := head[x];
    while(i > 0) do
    begin
        y := to1[i];
        if(fa[x] = y)then
        begin
            i := next[i];
            continue
        end;
        if(y = 0) then break;
        sx[y] := sx[x];
        if(qz[i] = 0)then
            dec(sx[y])
        else
            inc(sx[y]);
        i := next[i];
        repeat1(y);
    end;
end;

begin
    minn := maxlongint;
    readln(n);
    for i := 1 to n - 1 do
    begin
        readln(x, y);
        add1(x, y, 1);
        add1(y, x, 0);
    end;
    prework(1);
    init(1);
    repeat1(1);
    for i := 1 to n do
    begin
        if(sx[i] <= minn)then
        begin
            minn := sx[i];
            end1 := i;
        end;
    end;
    writeln(minn);
    for i := 1 to n do
        if(sx[i] = minn) and (end1 <> i) then
            write(i,' ');
    writeln(end1);
end.

T4

題目

題目描述
立刻假期就要到了,THU的神犇Leopard假期裏都不忘學霸,如今有好多門功課,每門功課都耗費他1單位時間來學習。
           他的假期從0時刻開始,有1000000000個單位時間(囧rz)。在任意時刻,他均可以任意一門功課(編號1~n)來學習。
           由於他在每一個單位時間只能學習一門功課,而每門功課又都有一個截止日期,因此他很難完成全部n門功課。
           對於第i門功課,有一個截止時間Di,若他能學完這門功課,他可以得到知識Pi。
           在給定的功課和截止時間下,Leopard可以得到的知識最多爲多少呢?
輸入
第一行,一個整數n,表示功課的數目
接下來n行,每行兩個整數,Di和Pi
輸出
輸出一行一個整數,表示最多學得的知識數
樣例輸入
3
2 10
1 5
1 7
樣例輸出
17

【樣例說明】
第一個單位時間學習第3個功課(1,7),而後在第二個單位時間學習第1個功課(2,10)

思路

本題的算法是貪心或DP,但我用的是堆(什麼鬼啊)。

一眼看下去,想都不用想,排個序,按時間來排。

我用的堆是小根堆,由於若是存不下(時間不夠),我是會拿當前最小的位置放新來的(必定要比最小的大啊!\(\Leftarrow\)廢話),固然堆這種東西是存一個,排(序)一個的(廢話×2)。

代碼

for (int i = 1; i <= n; i++)
{
    if(heap.size() < a[i].x) //時間夠
    {
        ans += a[i].y;
        heap.push(a[i].y);
    }
    else                     //時間不夠
    {
        if(heap.top() < a[i].y)   //並且比"最小的"大
        {
            ans -= heap.top();
            heap.pop();
            heap.push(a[i].y);
            ans += a[i].y;
        }
    }
}

讓咱們直接來到Day20

Q:在?爲啥咕咕。

A:我就是不寫,啊啊啊啊,寫這些一大堆,啊啊啊

Q:爲啥又開始寫了???

A:由於我想寫。。。

Q:在?爲啥B組

A:由於我想去。。。

T1

T1

T2 作夢

相關文章
相關標籤/搜索