比赛时有点事,赛后补了一下题

A 巨木之森
题意就不复述了, 这题的核心内容就是树的直径。
观察下面的图可以发现,一个点遍历整棵树的路程就是 所有的边*2 - 从这个点出发所到的最远距离。根据树的直径的性质,我们可以找到离所有点最远的两个点,然后就是简单的贪心问题了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;ll dis1[N], dis2[N], m, ans[N], sum, res;struct edge {int to, next, vi;
}e[N<<1];int n, h[N], cnt, p, q;void add(int u, int v, int w) {e[cnt].to = v;e[cnt].vi = w;e[cnt].next = h[u];h[u] = cnt++;
}void dfs1(int u, int fa) {if (dis1[p] < dis1[u]) p = u;for (int i = h[u]; ~i; i = e[i].next) {int v = e[i].to;if (v == fa) continue;dis1[v] = dis1[u] + e[i].vi;dfs1(v, u);}
}void dfs2(int u, int fa) {if (dis2[q] < dis2[u]) q = u;for (int i = h[u]; ~i; i = e[i].next) {int v = e[i].to;if (v == fa) continue;dis2[v] = dis2[u] + e[i].vi;dfs2(v, u);}
}int main() {memset(h, -1, sizeof h);scanf("%d %lld", &n, &m);for (int i = 1; i <= n - 1; i++) {int x, y, z;scanf("%d %d %d", &x, &y, &z);add(x, y, z), add(y, x, z);sum += z;}dfs1(1, 0);dfs2(p, 0);// p到个点的距离dis1[q] = 0;dfs1(q, 0);// q到个点的距离for (int i = 1; i <= n; i++) {ans[i] = sum * 2 - max(dis1[i], dis2[i]);}sort(ans + 1, ans + n + 1);if (m < ans[1]) {printf("0\n");return 0;}for (int i = 1; i <= n; i++) {res += ans[i];if (res > m) {printf("%d\n", i-1);return 0;}}printf("%d\n", n);
}

B 乐团派对
这题有两种解法,一种是贪心,一种是dp
贪心的思路是,从小到大贪心,提前先处理好最后一个最大的数,然后枚举乐队的数量即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int mod = 1e9;int n, sum;
int a[N];int main() {cin >> n;for (int i = 1; i <= n; i++) cin >> a[i];sort(a + 1, a + n + 1);if (a[n] > n)puts("-1");else {int r = n - a[n];int num = 0;sum = 1;for (int i = 1; i <= r; i++) {num++;if (num >= a[i]) {num = 0;sum++;}}printf("%d\n", sum);}
}

dp的思路是,我们设dp[i]表示前i个人最多可以组成多少乐队,当i > a[i] 时,我们可以将第i个人丢掉,让他们自己组成乐队,然后再加上i-a[i]个人最多组成的乐队数,当然,我们也可以把第i个人放入当前的乐队中。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int Mod = 1e9;
int n, a[N], dp[N];
int main() {cin >> n;for (int i = 1; i <= n; i++) cin >> a[i];sort(a + 1, a + n + 1);if (a[n] > n) {printf("-1\n");return 0;}for (int i = 1; i <= n; i++) {if (i >= a[i]) dp[i] = max(dp[i - a[i]] + 1, dp[i - 1]);else dp[i] = 0;}printf("%d", dp[n]);
}

C 光玉小镇
状压dp 咕咕咕

D 巅峰对决
维护区间问题,自然想到线段树的模型
题中的区间没有重复的值,因此如果区间内的数是连续的,那么可以通过比较区间的最大最小值之差和区间定义域之差是否相等就可以了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int a[N];struct SegementTree {int l, r;int max_, min_;
}t[N * 4];int n, m;void push_up(int u) {t[u].max_ = max(t[u << 1].max_, t[u << 1 | 1].max_);t[u].min_ = min(t[u << 1].min_, t[u << 1 | 1].min_);
}void build(int l, int r, int u) {t[u].l = l, t[u].r = r;t[u].max_ = 0, t[u].min_ = 0x3f3f3f3f;if (l == r) {t[u].max_ = a[l];t[u].min_ = a[l];return;}int mid = (l + r) >> 1;build(l, mid, u << 1);build(mid + 1, r, u << 1 | 1);push_up(u);
}void update(int u, int pos, ll v) {if (t[u].l == t[u].r) {t[u].min_ = v;t[u].max_ = v;return;}int mid = (t[u].l + t[u].r) >> 1;if (pos <= mid) update(u << 1, pos, v);else update(u << 1 | 1, pos, v);push_up(u);
}int query_min(int ql, int qr, int u) {if (ql <= t[u].l && t[u].r <= qr) {return t[u].min_;}int mid = (t[u].l + t[u].r) >> 1;int res = 0x3f3f3f3f;if (ql <= mid) res = min(res, query_min(ql, qr, u << 1));if (qr > mid) res = min(res, query_min(ql, qr, u << 1 | 1));return res;
}int query_max(int ql, int qr, int u) {if (ql <= t[u].l && t[u].r <= qr) {return t[u].max_;}int mid = (t[u].l + t[u].r) >> 1;int res = 0;if (ql <= mid) res = max(res, query_max(ql, qr, u << 1));if (qr > mid) res = max(res, query_max(ql, qr, u << 1 | 1));return res;
}int main() {ios::sync_with_stdio(0);cin >> n >> m;for (int i = 1; i <= n; i++) cin >> a[i];build(1, n, 1);while (m--) {int op, x, y;ll k;cin >> op >> x >> y;if (op == 1) {update(1, x, y);}else {int max_ = query_max(x, y, 1);int min_ = query_min(x, y, 1);if (y - x == max_ - min_) puts("YES");else puts("NO");}}
}

E 使徒袭来
纯签到,没什么好说的

#include <bits/stdc++.h>
using namespace std;
int n;
int main() {cin >> n;double l = 0, r = 1e9, mid;while (r - l > 1e-8) {mid = (l + r) * 0.5;if (mid * mid * mid < n) l = mid;else r = mid;}printf("%.3lf", 3 * mid);
}

F 核弹剑仙

稍微画一下图(略丑),用强的指向弱的,因此题目问有多少强于i的,其实就是有多少能到i的点
题目没有排除重边的可能,因此要用vis处理每个点只经过一次

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
vector<int> g[N];
int n, m;
int cnt[N], vis[N];
void dfs(int x) {cnt[x]++; vis[x] = 1;for (auto v : g[x]) {if (!vis[v])dfs(v);}
}int main() {ios::sync_with_stdio(0);cin >> n >> m;for (int i = 1; i <= m; i++) {int x, y;cin >> x >> y;g[x].push_back(y);}for (int i = 1; i <= n; i++) {memset(vis, 0, sizeof vis);dfs(i);}for (int i = 1; i <= n; i++) printf("%d\n", cnt[i]-1);
}

G 虚空之力
也是签到题

组合问题, 能用kinging就用, 剩下的用king
(开始还以为要连续的…kmp 哈希wa了好几发)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e7 + 10;
int n;
char str[N];
int k_, i_, n_, g_;
int main() {cin >> n;cin >> str;for (int i = 0; i < n; i++) {if (str[i] == 'k') k_++;else if (str[i] == 'i') i_++;else if (str[i] == 'n') n_++;else if (str[i] == 'g') g_++;}int sum = 0;int min_ = min(min(i_, n_), g_);if (k_ * 2 < min_) {sum += k_ * 2;}else {sum += min_ / 2 * 2;i_ -= min_ / 2*2;n_ -= min_ / 2*2;g_ -= min_ / 2*2;k_ -= min_ / 2;sum += min(min(min(g_, i_), n_), k_);}printf("%d", sum);
}

H 社团游戏
处理一下二维前缀和
用sum[i][j][k]表示到第i行第j列有多少个k字符
再用二分取正方形的边长, 并依次判断26个字符
复杂度在500* 500 * 26 *log500左右

#include <bits/stdc++.h>
using namespace std;
const int N = 510;
int sum[N][N][27];
char c;
int main() {ios::sync_with_stdio(0);int n, m, k;cin >> n >> m >> k;for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++) {cin >> c;sum[i][j][c - 'a' + 1] = 1;}for (int k = 1; k <= 26; k++)for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)sum[i][j][k] += sum[i - 1][j][k] + sum[i][j - 1][k] - sum[i - 1][j - 1][k];for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {int l = 1, r = min(n - i + 1, m - j + 1);while (l <= r) {int mid = (l + r) >> 1; int f = 0;for (int o = 1; o <= 26; o++) {if (sum[i + mid - 1][j + mid - 1][o] - sum[i + mid - 1][j - 1][o] - sum[i - 1][j + mid - 1][o] + sum[i - 1][j - 1][o] > k) {f = 1;break;}}if (f) r = mid - 1;else l = mid + 1;}printf("%d ", r);}puts("");}}

I 名作之壁
我们可以先固定左端点l,然后用两个单调队列维护区间的最大最小值,如果满足差大于k,那么[l, R], R ∈[r, n]这段区间内的都能满足,因此答案累加n-i+1,然后再将左端向右移动一个单位

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e7 + 10;
const int Mod = 1e9;int n, k;
ll a[N], b, c;
ll qMax[N], qMin[N];
ll ans, l;int main() {scanf("%d %d", &n, &k);scanf("%lld %lld %lld", &a[0], &b, &c);int l1 = 1, l2 = 1, r1 = 0, r2 = 0;l = 1;for (int i = 1; i <= n; i++) {a[i] = (a[i - 1] * b % Mod + c) % Mod;while (l1 <= r1 && a[qMax[r1]] <= a[i]) r1--;while (l2 <= r2 && a[qMin[r2]] >= a[i]) r2--;qMax[++r1] = qMin[++r2] = i;//cout << a[qMax[l1]] << " " << a[qMin[l2]] << endl;while (a[qMax[l1]] - a[qMin[l2]] > k) {ans += 1ll*(n - i + 1);l++;if (qMax[l1] < l) l1++;if (qMin[l2] < l) l2++;}}printf("%lld\n", ans);
}

J 逃跑路线
签到题

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, a[N];
int main() {cin >> n;int ji = 0, ou = 0;while (n--) {string s;cin >> s;if ((s[s.size() - 1] - '0') % 2 == 0) ou++;else ji++;}if (ji % 2 == 1) puts("1");else puts("0");
}

又水了一篇, レ(゚∀゚;)ヘ=3=3=3

牛客小白月赛27 题解相关推荐

  1. 牛客小白月赛27题解(部分)

    链接:https://ac.nowcoder.com/acm/contest/6874 来源:nowcoder 文章目录 A 巨木之森(树的直径) B 乐团派对(贪心) D 巅峰对决(线段树) E 使 ...

  2. 牛客小白月赛27 B.乐团派对

    牛客小白月赛27 B.乐团派对 题目链接 题目描述 音乐是带给大家快乐的存在,而你的目标就是组建若干支乐队,让世界听到你们的演奏! 你目前有 nnn 位乐手,每位乐手只能进入一个乐队,但并不是每位乐手 ...

  3. 牛客小白月赛19 题解

    牛客小白月赛19 A. 「水」滔天巨浪(思维) B. 「木」迷雾森林 (数字三角形模型) C. 「土」秘法地震(二维前缀和) F. 「水」悠悠碧波 (字符串) D. 「金」初心如金 (找规律) G. ...

  4. 牛客小白月赛27部分题解(持续更新)

    今天打了一场牛客网的小白月赛,只做出来3题,自己好菜,怎么办呢,只能记录下来,用以砥砺自己,多刷题.QAQ 比赛连接:连接 首先是E题 E-使徒袭来 题目描述 神秘的使徒袭击了第三新东京市,少男少女们 ...

  5. 牛客小白月赛 27部分题解

    已做BCDEFGJ B.乐团派对 刚开始想了个贪心,结果不对然后直接转头想dp了. 将能力值排序. 首先我们先分出来一组,能力值最大的分出来一组人数是ana_nan​即下标是n−an+1→nn-a_n ...

  6. 牛客小白月赛30题解

    A 黑白边 有n个点,m条边,每条边都分为黑边和白边,现在要选一些边,使得所有点都可以相互连通,要求用白边的条数最少. 看到所有的点都相互连通,就可以想到生成树,所以把所有的白边和黑边分类,先用黑色的 ...

  7. 牛客小白月赛65个人题解A-E

    1. 牛客小白月赛65 A. 牛牛去购物 题意:给定n元,购买价格为a元的篮球和价格为b的篮球,数量不定,要使得花掉的钱最多,也就是剩余的钱数最少,求这个值 (1 <= n, a, b < ...

  8. 牛客小白月赛60(A~C)题解

    原题地址:牛客小白月赛60_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ 题目A:小竹与妈妈 题意:输出(x-b)/a即可,没什么好说 代码: #include< ...

  9. F.孤独(牛客小白月赛39)

    F.孤独(牛客小白月赛39) 题意: 给定一棵树,寻找一个路径,将断掉所有与这个路径上的点相连的边,使得剩下的最大连通块的大小最小 题解: 这题有点印象,感觉做过,至少这个方法肯定遇到过 设dp[u] ...

最新文章

  1. 芯片短缺加剧,上半年汽车销量逆势上涨的丰田也扛不住了,9月减产40%
  2. 剑指offer-数组中出现次数超过一半的数字
  3. springboot+mongodb
  4. @CacheEvict 清除多个key
  5. 查看linux服务器硬件信息
  6. 大数据系列博客之 --- 深入简出 Shell 脚本语言(提升篇)
  7. 杨强教授领衔力作,《迁移学习》最新出炉,解决AI“最后一公里”问题 | 赠书...
  8. 【java学习之路】(java框架)001.Maven配置及使用
  9. array_filter移除空数组
  10. 如何给老年唱戏机下载有声小说
  11. 电脑锁屏壁纸提取方法
  12. c# 基于BouncyCastle.Crypto的国密sm2,sm4封装,与java版本兼容
  13. SPI读取NRF24L01
  14. linux usb网卡驱动 ko,qf9700 USB网卡在x86 linux和arm linux上的驱动安装以及配置
  15. 车联网上云最佳实践 七
  16. 初步使用bootstrap框架
  17. 射影几何--圆锥曲线在平面上某点确定的对合线束
  18. 开启Atcoder之路
  19. 【散文】 岁月留痕遇好友
  20. 中移M5311模块MQTT协议连接阿里云物联网平台(干货)

热门文章

  1. iphone12发布时间和上市时间
  2. 预训练语言模型整理(ELMo/GPT/BERT...)
  3. SQL注入 ----前置基础
  4. 【立创开源】ESP32 平衡车
  5. 数据库查询语句(二)-条件查询
  6. 极客头条8月份活跃成员奖励名单(20150909)
  7. 基于Halcon的图像拼接
  8. Nor Flash 学习笔记
  9. 一键清理大师 v5.6.0 安卓官方版
  10. pyecharts绘制地铁图_Python数据分析:柱形图的绘制方法