2023 河南 萌新联赛 第一场 河南农业大学

2023河南萌新联赛第(一)场:河南农业大学

测试时间:Wed Jul 13:00-17:00 CST 2023

战绩4/12

E 动物朋友

题目描述

已知有n个动物朋友排成一排,每个动物朋友都有一个正整数的快乐值,涛涛每次会和连续的动物朋友玩,并且获得这些动物朋友快乐值的和的快乐,而涛涛是个完美主义者,他觉得快乐值刚好是m时候才是快乐的,现在请问有多少种选择方式,使得所选的连续的动物朋友的快乐值刚好为m。

输入格式

第一行输入n(1<=n<=1e6)和m(1<=m<=1e6)。

第二行输入n个正整数,第i个代表第i个动物朋友的快乐值。(1<=ai<=1e5)

1 5
4
11 45
1 4 1 9 19 8 10 8 1 2 3
输出格式

一个整数,表示可能存在的选法数量,如果没有,就输出0;

0
1
解题思路
  1. 暴力枚举
  2. 前缀和 + 查找(二分,set)
AC代码
/**
 * \link: https://ac.nowcoder.com/acm/contest/61132/E
 * \category: 暴力枚举 前缀和 二分
 *
 * \date:
 * \author: YaeSaraki
 **/

#include <algorithm>
#include <iostream>
#include <vector>
#include <unordered_set>

using namespace std;
using ll = long long;

/** using 前缀和 & 二分. */
inline void solve2() {
  int n, m; cin >> n >> m;
  vector<ll> a(n + 1), presum(n + 1); // ! 注意presum数组要开 long long
  unordered_set<ll> s; // ! set集合同样要开longlong
  for (int i = 1; i <= n; ++i) {
    cin >> a.at(i);
    presum.at(i) = presum.at(i - 1) + a.at(i);
    s.insert(presum.at(i)); 
  }
  int ans = 0;
  for (int i = 1; i <= n; ++i) {
    if (s.count(presum.at(i - 1) + m)) ++ans;
  }
  cout << ans << '\n';
}

/** using 暴力枚举. */
inline void solve() {
  int n, m; cin >> n >> m;
  vector<int> a(n);
  for (int i = 0; i < n; ++i) cin >> a.at(i);
  int ans = 0;
  for (int i = 0; i < n; ++i) {
    int cnt = a.at(i);
    if (cnt == m) ++ans;
    for (int j = i + 1; j < n; ++j) {
      cnt += a.at(j);
      if (cnt == m) ++ans;
      if (cnt > m) break;
    }
  }
  cout << ans << '\n';
}

bool rt = false;
signed main() {
  ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
  freopen("test.in", "r", stdin);
#endif
  if (rt) { int T; cin >> T; while (T--) solve(); }
  else solve();
  return (0 ^ 0);
}

F 松鼠排序

题目描述

松鼠宝宝有一排n个大小不一的坚果,松鼠宝宝想把坚果从小到大排序,每次他会选择两个坚果a和b每次花费1点力气把这两个坚果交换,爱动脑筋的松鼠宝宝想知道他排完这n个坚果一共需要花费的最少力气是多少?

输入格式

第一行一个整数n代表坚果数
接下来一行n个整数代表每个坚果的大小(每个坚果大小都不一样,即大小为1-n的一个排列)
1<=n<=1e5
坚果大小x,1<=x<=n

 1 5
 4
11 45
1 4 1 9 19 8 10 8 1 2 3
输出格式

一个整数,表示可能存在的选法数量,如果没有,就输出0;

0
1
解题思路
  1. 并查集
AC代码
/**
 * \link: https://ac.nowcoder.com/acm/contest/61132/F
 * \category: 并查集
 *
 * \date:
 * \author: YaeSaraki
 **/

#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>

using namespace std;

vector<int> f;

/** using 并查集. */
inline void solve2() {
  int n; cin >> n;
  /** init. */
  vector<int> a(n + 1);
  f = a;
  iota(f.begin(), f.end(), 0);
  
  for (int i = 1; i <= n; ++i) {
    cin >> a.at(i);
    f.at(a.at(i)) = i;
  }
  int ans = 0;
  for (int i = 1; i <= n; ++i) {
    if (a.at(i) != i) {
      int t = f.at(i);
      swap(a.at(i), a.at(t));
      f.at(a.at(t)) = t;
      ++ans;
    }
  }
  cout << ans << '\n'; 
}


/** compressed version. */
inline void solve() {
  int n; cin >> n;
  vector<int> a(n + 1), b(n + 1);
  for (int i = 1; i <= n; ++i) {
    cin >> a.at(i);
    b.at(a.at(i)) = i;
  }
  int energy = 0;
  for (int i = 1; i <= n; ++i) {
    while (a.at(i) != i) {
      swap(a.at(i), a.at(a.at(i)));
      ++energy;
    }
  }
  cout << energy << '\n';
  return ;
}

bool rt = false;
signed main() {
  ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
  freopen("test.in", "r", stdin);
#endif
  if (rt) { int T; cin >> T; while (T--) solve(); }
  else solve();
  return (0 ^ 0);
}

G Reverse

题目描述

给定一个01串,咱们可以选择任意长度区间翻转。求翻转后能得到的最长连续1串长度。

输入格式

输入共2行。
第一行一个整数n(1≤n≤106)n(1≤n≤106)。
第二行一个长度为n的01序列。

10
0111001011
输出格式

输出一个整数,表示最长的长度。

5

翻转区间[5,10],翻转为0111110100。

解题思路

咱们可以纪录每个连续1子串, 提取前两个相加即为答案。

AC代码
/**
 * \link: https://ac.nowcoder.com/acm/contest/61132/G
 * \category: 暴力 
 * 
 * \date:
 * \author: YaeSaraki
 **/
#pragma GCC optimize("O2")


#include <algorithm>
#include <iostream>
#include <stack>
#include <vector>

#define DBG(x) cout << #x << " = " << (x) << '\n'

using namespace std;
using PI = pair<int, int>;

bool cmp(PI &A, PI &B) {
  int a = A.second - A.first;
  int b = B.second - B.first;
  if (a != b) return  a > b; 
  return false;
}

inline void solve() {
  int n; cin >> n;
  string str; cin >> str;
  n = str.size();
  vector<PI> v;
  for (int i = 0; i < n; ++i) {
    int l = i;
    while (i < n && str.at(i) == '1') ++i;
    if (l != i) v.push_back({l, i});
  }

  if (v.size()) {
    if (v.size() == 1) return cout << v[0].second - v[0].first << '\n', void();
    sort(v.begin(), v.end(), cmp);
    cout << v[0].second - v[0].first + v[1].second - v[1].first << '\n';
  } else {
    cout << "0\n";
  }
  return ;
}

bool rt = false;
signed main() {
  ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
  freopen("test.in", "r", stdin);
#endif
  if (rt) { int T; cin >> T; while (T--) solve(); }
  else solve();
  return (0 ^ 0);
}

H 迷宫探险

题目描述

有一个n * m的迷宫,迷宫中道路用’.’表示,墙壁则由‘#’表示。小蓝初始在[1,1]的位置,他只有到达[n,m]才能开启最终的宝藏。小蓝现在迫不及待的想要开启宝藏,所以他想最短的时间内走出迷宫。现在迷宫内有一种特殊的装置 –“弹射器”。弹射器的格子用 * 表示。当走到有弹射器的一格时,必须选择一个方向,弹射器会沿着这个方向弹射 x个距离,不同弹射器的弹射距离可以不同。弹射后的格子如果超过迷宫边界或者是墙壁则不能选择这个方向。现在可以向上下左右四个方向走,每走一个格子需要消耗一个单位时间,弹射则不消耗时间。求最短需要多少时间,若无法达到输出-1

输入格式

第一行两个整数 n, m,接下来n行,每行m个只包含\’.\’,\’*\’,\’#\’的字符描绘迷宫。

接下来一行一个整数k,下面的k行每行三个整数x, y, w表示在[x,y]格子的弹射器能弹射的距离。(_2≤n≤3000,2≤m≤3_000,_n*m≤500000, 0≤k, w在int范围内_

3 2
.*
#.
..
1
1 2 2
2 2
.*
#.
1
1 2 2
输出格式

一行一个整数

1
-1
解题思路

根据题意,有两种连接方式。对于每个 . ,设边权为1,对于每个 * ,设边权为0,向周围四个方向建边,如果另一边为 # 则不建此边。

  • 在[1, 1]处开始,到[n, m]处结束。
AC代码
/**
 * \link: https://ac.nowcoder.com/acm/contest/61132/H
 * \category: 最短路
 *
 * \date:
 * \author: YaeSaraki
 **/

#pragma GCC optimize(2)
#include <algorithm>
#include <iostream>
#include <queue>

using namespace std;
using PI = pair<int, int>;

vector<vector<char> > miniMap;
vector<vector<int> > jumpEngine, point;
vector<pair<int, int> > dis = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

inline void solve() {
  /** init. */
  int n, m; cin >> n >> m;
  miniMap = vector<vector<char> >(n + 2, vector<char> (m + 2));
  point = vector<vector<int> >(n + 2, vector<int> (m + 2));
  jumpEngine = vector<vector<int> >(n + 2, vector<int> (m + 2));
  for (int i = 1; i <= n; ++i) 
    for (int j = 1; j <= m; ++j) 
      cin >> miniMap[i][j];
  int num; cin >> num;
  for (int i = 0; i < num; ++i) {
    int y, x, dis; cin >> y >> x >> dis;
    jumpEngine[y][x] = dis;
  }

  /** BFS. */
  queue<PI> que;
  que.push({1, 1});
  while (que.size()) {
    auto now = que.front();
    que.pop();
    int y_now = now.first, x_now = now.second;
    int jump = (jumpEngine[y_now][x_now] ? jumpEngine[y_now][x_now] : 1);
    int step = (jumpEngine[y_now][x_now] == 0 ? 1 : 0);
    for (auto [dx, dy] : dis) {
      int x = x_now + dx * jump;
      int y = y_now + dy * jump;
      if (x < 1 || y < 1 || x > m || y > n) continue;
      if (miniMap[y][x] == '#') continue;
      if (point[y][x] <= point[y_now][x_now] + step && point[y][x]) continue;
      point[y][x] = point[y_now][x_now] + step;
      que.push({y, x});
    }
  }
  if (point[n][m]) cout << point[n][m] << '\n';
  else cout << "-1\n";
  return;
}

bool rt = false;
signed main() {
  ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
  freopen("test.in", "r", stdin);
#endif
  if (rt) { int T; cin >> T; while (T--) solve(); }
  else solve();
  return (0 ^ 0);
}

J 合唱比赛

题目描述

河南农业大学信管学院举办一年一度的合唱比赛,目前你是评委之一,剩下还有其他的n位评委,给定一个正整数n和n个正整数表示这n个评委给目前在表演的团队的分数,评分规则为在所有评委(包括你)的分数中去掉一个最高分和最低分,剩下的取平均值(总共n-1个值),现在你可以参与评分(1~100之间的整数),问最终结果会在什么区间内,用两个数表示这个区间,结果保留6位小数。

输入格式

第一行给定一个正整数n
接下来一行给定n个整数表示n个评委的分数
2<=n<=1000

3
80 90 100
4
3 5 9 13
输出格式

输出两个保留六位的小数l,r表示答案。

85.000000 95.000000
5.666667 9.000000
解题思路

求最大和最小分数, 影响因素就是咱自己。

  • 最大分数即自己给出最高分101分并剔除。
  • 最小分数即自己给出最低分-1分并剔除。
AC代码
/**
 * \link: https://ac.nowcoder.com/acm/contest/61132/J
 * \category: 暴力枚举
 *
 * \date:
 * \author: YaeSaraki
 **/

#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;

inline void solve() {
  int n; cin >> n;
  vector<int> vote(n);
  for (int i = 0; i < n; ++i) cin >> vote.at(i);
  sort(vote.begin(), vote.end());
  vector<int> tempScore(vote);
  tempScore.pop_back();
  double min_score = 0;
  for (auto it : tempScore) min_score += it;
  min_score = 1.0 * min_score / (n - 1);
  printf("%.6lf ", min_score);
  
  tempScore = vote;
  tempScore.erase(tempScore.begin());
  double max_score = 0;
  for (auto it : tempScore) max_score += it;
  max_score = 1.0 * max_score / (n - 1);
  printf("%.6lf\n", max_score);
  return;
}

/** compressed version. */
inline void solve2() {
  int n; cin >> n;
  vector<int> vote(n);
  for (int i = 0; i < n; ++i) cin >> vote.at(i);
  sort(vote.begin(), vote.end());
  int sum = 0;
  for (int num : vote) sum += num;
  double min_score = (double)(sum - *vote.rbegin()) / (n - 1);
  double max_score = (double)(sum - *vote.begin()) / (n - 1);
  printf("%.6lf %.6lf", min_score, max_score);
}

bool rt = false;
signed main() {
  // ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
  freopen("test.in", "r", stdin);
#endif
  if (rt) { int T; cin >> T; while (T--) solve(); }
  else solve();
  return (0 ^ 0);
}

K 以撒和隐藏房间

题目描述

你说得对,但是以撒的结合是一款集合了推箱子、血统检验、少女换装、宠物养成等等元素的地牢探险/Rougelike类跨世代大作。游戏发生在以撒和他的妈妈住的小房子的[地下室]里,在这里,天真的以撒受[教条]的影响,进入了一场幻想中的地下室冒险。你将扮演以撒扮演的圣经中的人物,在充满怪物和杂物的地下室里获取各种激起回忆的道具,靠败们击败天使或是恶魔的阻挡,找回缺失的亲情——同时,逐步发掘[父母离异]的真相。以撒又一次的逃进了地下室。

地下室可以看作一个n*\m的矩阵的迷宫,其中有些格子是有门相连房间,有些则是无法通过的墙壁。以撒发现其中一些墙壁似乎是空心的,可以通过爆炸打开隐藏的房间,而隐藏房的生成有一定的规律,以撒认为一个墙壁格子在满足以下所有情况时可能会是隐藏房间:

  1. 该墙壁格子和三个普通房间相邻
  2. 在满足1条件的情况下,不能和boss房间相邻
    但是以撒正在和萌死戳交战,
    现在你需要编写程序告诉他是否存在可能是隐藏房间的格子。
输入格式

第一行两个整数n,m(3<m,n<=1000)
然后是一个n*m矩阵,表示地图状态,0表示墙壁,1表示房间,2表示boss房间

3 3
001
110
211
3 4
0010
1111
0102
输出格式

如果存在,输出两行,
第一行是一个YES,第二行输出可能为隐藏房间的格子的数量

如果不存在,输出一行,
输出NO

YES
1
NO
AC代码
/**
 * \link:https://ac.nowcoder.com/acm/contest/61132/K
 * \category: 暴力
 *
 * \date:
 * \author: YaeSaraki
 **/

#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;
using PI = pair<int, int>;

vector<vector<char> > miniMap;
vector<PI> direction = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

bool isSecretRoom(int y, int x) {
  int normal_room = 0;

  for (auto [dx, dy] : direction) {
    int x_now = x + dx, y_now = y + dy;
    if (miniMap[y_now][x_now] == '2') return false;
    if (miniMap[y_now][x_now] == '1') ++normal_room;
  }
  if (normal_room == 3) return true;
  return false;
}

inline void solve() {
  int n, m; cin >> n >> m;
  miniMap = vector<vector<char> >(n + 2, vector<char> (m + 2));
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
      cin >> miniMap.at(i).at(j);
    }
  }

  int ans = 0;
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
      if (miniMap[i][j] == '0' && isSecretRoom(i, j))
        ++ans;
    }
  }

  if (ans) cout << "YES\n" << ans << '\n';
  else cout << "NO\n";
  return ;
}

bool rt = false;
signed main() {
  ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
  freopen("test.in", "r", stdin);
#endif
  if (rt) { int T; cin >> T; while (T--) solve(); }
  else solve();
  return (0 ^ 0);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值