首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >信奥赛-刷题笔记-栈篇-T3-P2866Bad Hair Day S坏运连连的一天0522

信奥赛-刷题笔记-栈篇-T3-P2866Bad Hair Day S坏运连连的一天0522

原创
作者头像
IT从业者张某某
发布2025-05-22 11:08:32
发布2025-05-22 11:08:32
9800
代码可运行
举报
运行总次数:0
代码可运行

总题单

本部分总题单如下

【腾讯文档】副本-CSP-JS+NOI 题单 (未完待续)

https://docs.qq.com/sheet/DSmJuVXR4RUNVWWhW?tab=BB08J2

栈篇题单

P2866 USACO06NOV Bad Hair Day S坏运连连的一天

https://www.luogu.com.cn/problem/P2866

题目描述

农夫约翰有 N 头奶牛正在过乱头发节。

每一头牛都站在同一排面朝右,它们被从左到右依次编号为 1, 2, \cdots, N 。编号为 i 的牛身高为 h_i 。第 N 头牛在最前面,而第 1 头牛在最后面。

对于第 i 头牛前面的第 j 头牛,如果 h_i>h_{i+1}, h_i>h_{i+2}, \cdots, h_i>h_j ,那么认为第 i 头牛可以看到第 i+1 到第 j 头牛。

定义 C_i 为第 i 头牛所能看到的牛的数量。请帮助农夫约翰求出 C _ 1 + C _ 2 + \cdots + C _ N

输入格式

输入共 N + 1 行。

第一行为一个整数 N ,代表牛的个数。

接下来 N 行,每行一个整数 a _ i ,分别代表第 1, 2, \cdots, N 头牛的身高。

输出格式

输出共一行一个整数,代表 C _ 1 + C _ 2 + \cdots + C _ N

输入输出样例 #1

输入 #1

代码语言:txt
复制
6
10
3
7
4
12
2

输出 #1

代码语言:txt
复制
5

说明/提示

数据规模与约定

对于 100\% 的数据,保证 1 \leq N \leq 8 \times 10 ^ 41 \leq h _ i \leq 10 ^ 9

代码1 用暴力

代码语言:cpp
代码运行次数:0
运行
复制
#include <bits/stdc++.h>
using namespace std;

const int maxn = 8e4 + 10; // 最多 80000 头牛

int n, ans;
int h[maxn]; // 存储每头牛的身高

int main() {
    // 输入牛的数量
    cin >> n;

    // 输入每头牛的身高,h[1] 是第一头牛,h[n] 是最后一头牛
    for (int i = 1; i <= n; ++i) {
        cin >> h[i];
    }

    // 对于每一头牛 i,从它右边开始找连续比它矮的牛
    for (int i = 1; i <= n - 1; ++i) {
        int count = 0; // 当前牛能看到的牛的数量
        for (int j = i + 1; j <= n; ++j) {
            if (h[i] > h[j]) {
                count++;
            } else {
                break; // 一旦遇到不比它矮的,后面就看不到了
            }
        }
        ans += count;
    }

    // 输出总和
    cout << ans << endl;

    return 0;
}

代码2

当然可以!下面是你提供的代码,我将为它添加完整详细的注释,帮助你理解它的每一步操作。


✅ 题目回顾

这道题要求我们计算每一头牛能看到的“右侧连续比它矮”的牛的数量之和。

使用 单调栈(递减栈) 可以高效地解决这个问题。


🧾 完整带注释的代码如下:

代码语言:cpp
代码运行次数:0
运行
复制
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

// 常量定义(虽然没有用到 M 和 MOD,但可能是模板代码)
constexpr int N = 8e4,  MAX_N = N + 10;

int n;           // 牛的数量
int height;     // 用于存储当前牛的身高
ll ans = 0;      // 答案变量,记录所有牛能看到的总数

// 函数:禁用 C++ 的同步流,加快输入输出速度
void disable_sync()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
}

stack<int> cows; // 单调栈:保存的是当前牛右边的、可能被看到的牛的身高(保持栈是递减的)

int main()
{
    // 禁用同步流,提高读写效率
    disable_sync();

    // 输入牛的数量
    cin >> n;

    // 从左到右依次读入每头牛的身高
    for (int i = 1; i <= n; ++i)
    {
        cin >> height;

        // 当前牛的身高 >= 栈顶元素时,说明栈顶的牛会被当前牛挡住
        // 所以它们不可能再被更左边的牛看到,因此弹出
        while (!cows.empty() && height >= cows.top())
        {
            cows.pop();
        }

        // 此时栈中剩下的都是比当前牛高的,所以当前牛可以看到这些牛
        ans += cows.size();

        // 把当前牛压入栈中,供后续更左边的牛判断使用
        cows.push(height);
    }

    // 输出最终的答案
    cout << ans << endl;

    return 0;
}

📌 示例分析

输入:

代码语言:txt
复制
6
10
3
7
4
12
2

模拟栈变化过程:

当前牛身高

栈状态(栈底 → 栈顶)

能看到的牛数

累计 ans

10

10

0

0

3

10, 3

1

1

7

10, 7

1

2

4

10, 7, 4

2

4

12

12

0

4

2

12, 2

1

5

✅ 最终输出 ans = 5,与题目样例一致。


✅ 总结

  • 这个解法利用了 单调栈,时间复杂度为 $O(N)$;
  • 每头牛只会进栈一次、出栈最多一次;
  • 栈中保存的是能被当前牛看到的牛的身高;
  • 如果当前牛比栈顶高,则栈顶牛不会被看到,弹出;
  • 最终栈的大小就是当前牛能看到的牛的数量。

如果你还想了解这个算法背后的原理,或者想练习类似题目(如“可见山峰对”、“直方图最大矩形”等),我可以继续为你提供讲解。是否需要?

现场真题注意事项

https://cspoj.com/contest.php?cid=1002Fus5yz4x3EcSJH1Z

注意事项

文件名(程序名和输入输出文件名)必须使用英文小写。(提交必须使用freopen()进行提交)

C/C++ 中函数 main() 的返回值类型必须是 int,程序正常结束时的返回值必须是0。

提交的程序代码文件的放置位置请参考各省的具体要求。

因违反以上三点而出现的错误或问题,申述时一律不予受理。

若无特殊说明,结果的比较方式为全文比较(过滤行末空格及文末回车)。

程序可使用的栈空间内存限制与题目的内存限制一致。

全国统一评测时采用的机器配置为:Inter® Core™ i7-8700K CPU @3.70GHz,内存 32GB。上述时限以此配置为准。

只提供 Linux 格式附加样例文件。

评测在当前最新公布的 NOI Linux 下进行,各语言的编译器版本以此为准

假设输入样例数据存在文件test.in中,输出样例数据存在文件test.out中,

则在CSP、NOI等比赛的代码中,需添加freopen、fclose语句,

内容详见模板代码如下。

代码语言:cpp
代码运行次数:0
运行
复制
#include <bits/stdc++.h>
#include<cstdio>//必须包含cstdio头文件
#include<iostream>
using namespace std;
 
int main(){
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	
	cout<<"Hello NOI"<<endl;
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}

复制

下面为函数的简介,详细可参见 http://www.cplusplus.com/reference/clibrary/cstdio/freopen.html

函数名:freopen

声明:

代码语言:cpp
代码运行次数:0
运行
复制
FILE _freopen( const char_ path, const char _mode, FILE_ stream );

所在文件: stdio.h

参数说明:

path: 文件名,用于存储输入输出的自定义文件名。

mode: 文件打开的模式。和fopen中的模式(如r-只读, w-写)相同。

stream: 一个文件,通常使用标准流文件。

返回值:成功,则返回一个path所指定文件的指针;失败,返回NULL。(一般可以不使用它的返回值)

功能:实现重定向,把预定义的标准流文件定向到由path指定的文件中。标准流文件具体是指stdin、stdout和stderr。其中stdin是标准输入流,默认为键盘;stdout是标准输出流,默认为屏幕;stderr是标准错误流,一般把屏幕设为默认。通过调用freopen,就可以修改标准流文件的默认值,实现重定向。

代码语言:cpp
代码运行次数:0
运行
复制
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
    freopen("7532.in", "r", stdin);
    freopen("7532.out", "w", stdout);
    //原来的代码保持不变
    double a, b, r;
    int k;
    cin >> a >> b;
    k = int(a/b);
    r = a - b * k;
    printf("%g", r);
    //-------------
    fclose(stdin);
    fclose(stdout);
    return 0;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 总题单
  • 栈篇题单
  • P2866 USACO06NOV Bad Hair Day S坏运连连的一天
    • 题目描述
    • 输入格式
    • 输出格式
    • 输入输出样例 #1
      • 输入 #1
      • 输出 #1
    • 说明/提示
      • 数据规模与约定
    • 代码1 用暴力
    • 代码2
    • ✅ 题目回顾
    • 🧾 完整带注释的代码如下:
    • 📌 示例分析
      • 输入:
      • 模拟栈变化过程:
    • ✅ 总结
  • 现场真题注意事项
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档