【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 作梦

相关文章
相关标签/搜索