学习总结5

# [NOIP2010 普及组] 接水问题

## 题目描述

学校里有一个水房,水房里一共装有 m 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为 1。

现在有 n 名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从 1 到 n 编号,i 号同学的接水量为 wi。接水开始时,1 到 m 号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学 j 完成其接水量要求 wj 后,下一名排队等候接水的同学 k 马上接替 j 同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即 j 同学第 x 秒结束时完成接水,则 k 同学第 x+1 秒立刻开始接水。若当前接水人数 n 不足 m,则只有 n 个龙头供水,其它 m - n 个龙头关闭。

现在给出 n 名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。

## 输入格式

第一行两个整数 n 和 m,用一个空格隔开,分别表示接水人数和龙头个数。

第二行 n 个整数 w1,w2,……,wn,每两个整数之间用一个空格隔开,wi 表示 i 号同学的接水量。

## 输出格式

一个整数,表示接水所需的总时间。

## 样例 #1

### 样例输入 #1

```
5 3
4 4 1 2 1
```

### 样例输出 #1

```
4
```

## 样例 #2

### 样例输入 #2

```
8 4
23 71 87 32 70 93 80 76
```

### 样例输出 #2

```
163
```

## 提示

【输入输出样例 1 说明】

第 1 秒,3 人接水。第 1 秒结束时,1,2,3 号同学每人的已接水量为 1,3 号同学接完水,4 号同学接替 3 号同学开始接水。

第 2 秒,3 人接水。第 2 秒结束时,1,2 号同学每人的已接水量为 2,4 号同学的已接水量为 1。

第 3 秒,3 人接水。第 3 秒结束时,1,2 号同学每人的已接水量为 3,4 号同学的已接水量为 2。4 号同学接完水,5 号同学接替 4 号同学开始接水。

第 4 秒,3 人接水。第 4 秒结束时,1,2 号同学每人的已接水量为 4,5 号同学的已接水量为 1。1,2,5 号同学接完水,即所有人完成接水的总接水时间为 4 秒。

【数据范围】

1 <= n <= 10^4,1 <= m <= 100,m <= n;

1 <= wi <= 100。

NOIP2010 普及组 第二题

解题思路

拿每一个水龙头都对应一个同学,每当有人打完水就重新找一个。

代码

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int g[1100000];
int main()
{
    int x,y,z,n,m,t=0;
    scanf("%d%d",&n,&m);
    for(x=0;x<n;x++)
    {
        scanf("%d",&g[x]);
    }
    y=m;
    while(y<n+m)                           //当所有水龙头都找不到匹配的人就停止
    {
        for(x=0;x<m;x++)
        {
            g[x]--;
            if(g[x]==0)
            {
                g[x]=g[y++];
            }
        }
        t++;
    }
    printf("%d",t);
    return 0;
}

# 高手去散步

## 题目背景

高手最近谈恋爱了。不过是单相思。“即使是单相思,也是完整的爱情”,高手从未放弃对它的追求。今天,这个阳光明媚的早晨,太阳从西边缓缓升起。于是它找到高手,希望在晨读开始之前和高手一起在鳌头山上一起散步。高手当然不会放弃这次梦寐以求的机会,他已经准备好了一切。

## 题目描述

鳌头山上有 n 个观景点,观景点两两之间有游步道共 m 条。高手的那个它,不喜欢太刺激的过程,因此那些没有路的观景点高手是不会选择去的。另外,她也不喜欢去同一个观景点一次以上。而高手想让他们在一起的路程最长(观景时它不会理高手),已知高手的穿梭机可以让他们在任意一个观景点出发,也在任意一个观景点结束。

## 输入格式

第一行,两个用空格隔开的整数 n 、 m 之后 m 行,为每条游步道的信息:两端观景点编号、长度。

## 输出格式

一个整数,表示他们最长相伴的路程。

## 样例 #1

### 样例输入 #1

```
4 6
1 2 10
2 3 20
3 4 30
4 1 40
1 3 50
2 4 60
```

### 样例输出 #1

```
150
```

## 提示

对于 100% 的数据:n <= 20,m <= 50,保证观景点两两之间不会有多条游步道连接。

解题思路

运用dfs,进行搜索。要注意的是所有的游步道都是双向的,所以每一个游步道都要进行两次赋值。

代码

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int j[110];
int max1;
struct
{
    int x;
    int y;
    int d;
}g[110];
int n,m;
int dfs(int k,int y)
{
    int x;
    for(x=0;x<m*2-1;x++)
    {
        if(g[x].x==k&&j[g[x].y]!=1)
        {
            j[g[x].x]=1;
            y=y+g[x].d;
            if(y>max1)
                max1=y;                          //保存最大的值
            dfs(g[x].y,y);
            j[g[x].x]=0;
            y=y-g[x].d;
        }
    }
    return 0;
}
int main()
{
    int x,y,z,a;
    scanf("%d%d",&n,&m);
    for(x=0;x<m;x++)
    {
        scanf("%d%d%d",&g[x].x,&g[x].y,&g[x].d);
        g[m+x].x=g[x].y;                             //进行两方的赋值,使得游步道成为双向的
        g[x+m].y=g[x].x;
        g[x+m].d=g[x].d;
    }
    for(x=1;x<=n;x++)
    {
        j[x]=1;                                   //以每一个景点为起点
        dfs(x,0);
        j[x]=0;
    }
    printf("%d",max1);
    return 0;
}

# 日志分析

## 题目描述

M 海运公司最近要对旗下仓库的货物进出情况进行统计。目前他们所拥有的唯一记录就是一个记录集装箱进出情况的日志。该日志记录了两类操作:第一类操作为集装箱入库操作,以及该次入库的集装箱重量;第二类操作为集装箱的出库操作。这些记录都严格按时间顺序排列。集装箱入库和出库的规则为先进后出,即每次出库操作出库的集装箱为当前在仓库里所有集装箱中最晚入库的集装箱。

出于分析目的,分析人员在日志中随机插入了若干第三类操作――查询操作。分析日志时,每遇到一次查询操作,都要报告出当前仓库中最大集装箱的重量。

## 输入格式

包含 N+1 行:

第一行为一个正整数 N,对应于日志内所含操作的总数。

接下来的 N 行,分别属于以下三种格式之一:

- 格式 1:`0 X`,表示一次集装箱入库操作,正整数 X 表示该次入库的集装箱的重量。
- 格式 2:`1`,表示一次集装箱出库操作,(就当时而言)最后入库的集装箱出库。
- 格式 3:`2`,表示一次查询操作,要求分析程序输出当前仓库内最大集装箱的重量。

当仓库为空时你应该忽略出库操作,当仓库为空查询时你应该输出 0。

## 输出格式

输出行数等于日志中查询操作的次数。每行为一个整数,表示查询结果。

## 样例 #1

### 样例输入 #1

```
13
0 1
0 2
2
0 4
0 2
2
1
2
1
1
2
1
2
```

### 样例输出 #1

```
2
4
4
1
0
```

## 提示

### 数据范围及约定

- 对于 20% 的数据,有 N <= 10;
- 对于 40% 的数据,有 N <= 1000;
- 对于 100% 的数据,有 1 <= N <= 200000,1 <= X <= 10^8。

解题思路

我一开始以为是普通的栈模拟题,写完发现这样会超时。看题解发现我们不用去查找或记录最大值,只要把当前的最大值入栈就行了。

代码

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
long long g[200001];
int main()
{
    long long x,y,z,n,r=0,t=0;
    scanf("%lld",&n);
    for(x=0;x<n;x++)
    {
        scanf("%lld",&y);
        if(y==0)
        {
            scanf("%lld",&z);
            r++;
            g[r]=g[r-1]>z?g[r-1]:z;            //把当前的最大值赋值入栈
        }
        if(y==1)
        {
            if(r>=0)
            {
                r--;
            }

        }
        if(y==2)
        {
            printf("%lld\n",g[r]);
        }
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值