比赛题目链接

感谢wb学长贡献的 B、L题解

A. NANA与字符串—找规律

题目链接

注意题目中 字符串中只有a,b两个字符
因此只要找到左右两端点字符相同的子串,这个子串一定回文,这里不在证明
求长为偶数回文串数量,就等于求相同的两个字符,而下标奇偶性不同的数对数量,比如0, 1 两个下标都是‘a’,这是偶数回文
同理 求长度为奇数回文,等于求下标奇偶性相同的数对数量
求奇数时需要注意,因为奇偶性相同是同类,求数对数量即求组合数n*(n - 1)/ 2 最后加上每个单个的字符
偶数不需要除以2是因为奇偶性不同,不会重复

#include <iostream>
#include <cstring>
using namespace std;
#define int long long
signed main()
{string s; cin >> s;int a1 = 0, a2 = 0, b1 = 0, b2 = 0;for(int i = 0; i < s.size(); i ++){a1 += (s[i] == 'a' && (i & 1));a2 += (s[i] == 'a' && !(i & 1));b1 += (s[i] == 'b' && (i & 1));b2 += (s[i] == 'b' && !(i & 1));}int res = a1 * a2 + b1 * b2;cout << res << ' ';    res = (a1 - 1) * a1 / 2 + (a2 - 1) * a2 / 2 + (b1 - 1) * b1 / 2 + (b2 - 1) * b2 / 2;cout << res + s.size() << '\n';
}

B. NANA学跳舞 — 字典树

题目链接

对于给定的下界 k k k,可以发现如下性质.

性质1

以 k = 8 k=8 k=8为例,一个二进制数的二进制位可以分为k的最高位(1000)前的k的最高位后的.例如,16是最高位前的二进制位、4和8是最高位后的二进制位。

对于两组二进制数,可以证明,如果当前的二进制位数 u u u比k的最高位靠前,那么这两个二进制数在 u u u上的取值对答案不构成影响. 证明如下:

设其一组 A A A在 u u u的下一位上取0,另一组 B B B在 u u u的下一位上取1. 那么任意 a ∈ A , b ∈ B , a x o r b > = k . a \in A, b\in B, a \space xor \space b >= k. a∈A,b∈B,a xor b>=k. 同时,由于任两个元素的异或也要 > = k >=k >=k,这就要求 A A A组内两两异或也要符合要求. 实际上,答案的个数就是 A A A组内合法的个数+ B B B组内合法的个数.

小结1

实际上,上面的性质可以转化成如下做法.

维护一棵字典树,对于比k的最高位高的位数,它的答案等于:

左子树的答案+右子树的答案. [ 1 ] ^{[1]} [1]

这样问题就转化为,对于一棵任意位都比k的最高位低的字典树,如何维护它的答案,使得结果 > = k >=k >=k?

[ 1 ] [1] [1]如果某一棵子树没有答案,由于左右子树异或之后的答案也合法,此时如果这棵子树有儿子,就可以强行使这棵树的答案取1.

性质2

对于上述的一棵低位字典树,其对答案的贡献只能是0或2.

证明如下.

对于任意二元组,要使它们的答案大于 k k k,就一定要有k的最高位上的结果是1,也就是说,这两个数在二进制的那一位上一个是0、一个是1.

这样答案就不可能>=3. 因为这样就一定会有两个元素在k的最高位上取得相同的结果,异或值也就不可能 > = k >=k >=k.

如果找不到这样的元组,答案为0.

问题就转化为,对于给定树根的字典树,是否存在二元组的异或值 > = k >=k >=k?

小结2

这是一个比较熟悉的问题. 我们可以转化问题为,求异或的最大值是否比 k k k大. 利用字典树即可解决.

总之,对于字典树内的每个节点我们都访问了一次,最终的复杂度为 O ( n ∗ l o g ( 2 30 ) ) O(n*log(2^{30})) O(n∗log(230))

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define int long long
const int N = 300010;
int n, m, tr[N * 30][2], idx;void add(int c)
{int root = 0;for (int i = 29; i >= 0; i --) {int cur = ((c >> i) & 1);if (!tr[root][cur]) tr[root][cur] = ++ idx;root = tr[root][cur];}
}int tot;vector<int> res;void dfs2(int u, int cur)
{if (!tr[cur][0] && !tr[cur][1]) {int root = u; int ans = 0;for (auto c: res) {ans = ans * 2;if (tr[root][!c]) ans += 1, root = tr[root][!c];else root = tr[root][c];}tot = max(tot, ans);return;}if (tr[cur][0]) {res.push_back(0);dfs2(u, tr[cur][0]);res.pop_back();}if (tr[cur][1]) {res.push_back(1);dfs2(u, tr[cur][1]);res.pop_back();}
}int dfs(int u, int k)
{int next = (1LL << (k - 1));if (next > m) {int p1 = 0, p2 = 0;if (tr[u][0]) p1 = dfs(tr[u][0], k - 1);if (tr[u][1]) p2 = dfs(tr[u][1], k - 1);if (tr[u][0] && tr[u][1])return max(1LL, p1) + max(1LL, p2);else return p1 + p2;} else {tot = 0;dfs2(u, u);return (tot >= m)? 2: 0;}
}signed main() {cin >> n >> m;while (n --) {int x; cin >> x;add(x);}int p = dfs(0, 30);cout << (p == 0? -1: p);
}

C. NANA去上课 — 简单数学

需要记录上一步处在哪个位置
然后判断如果是同一侧移动距离就是abs(x1 - x2)
如果不同就是x1 + x2

#include <iostream>
#include <cmath>
using namespace std;
#define int long long
signed main()
{int n; cin >> n;char s, pres; int x, prex; cin >> pres >> prex;int res = prex;for(int i = 2; i <= n; i ++){cin >> s >> x;if(pres != s) res += x + prex;else res += abs(prex - x);pres = s, prex = x;}res += prex;cout << res << '\n';
}

D. NANA在夜市 — bfs

倒着思考,从终点往周围扩展,判断能否到达,把能到达的点放入队列,接着扩展
这里判断时需要注意从能到达的点往外扩展时 方向是反着的,判断能否到达需要反着判断

#include <iostream>
#include <queue>
using namespace std;
const int N = 1010;
char g[N][N];
bool st[N][N];
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, 1, -1};signed main()
{int n, m; cin >> n >> m;for(int i = 0; i < n; i ++) cin >> g[i];int sx, sy;// 找到终点位置 for(int i = 0; i < n; i ++)for(int j = 0; j < m; j ++)if(g[i][j] == 'O')sx = i, sy = j;queue<pair<int,int>> q;q.push({sx, sy});st[sx][sy] = true;int res = 1;while(q.size()){int x = q.front().first;int y = q.front().second;q.pop();for(int i = 0; i < 4; i ++){int ax = x + dx[i];int ay = y + dy[i];if(ax < 0 || ax >= n || ay < 0 || ay >= m || st[ax][ay]) continue;if((i == 0 && g[ax][ay] == 'D') || (i == 1 && g[ax][ay] == 'U') || (i == 2 && g[ax][ay] == 'L') || (i == 3 && g[ax][ay] == 'R')) {q.push({ax, ay});st[ax][ay] = true;res ++;}}}cout << res << '\n';}

E.


F. NANA 的排名 — 二分+排序

先按照每个人的最低分加入到总成绩,用两个数组记录,一个原始数组,一个按总成绩从大到小排序的数组
遍历每一个人,用二分在在已经排序的数组里找到比它的数的数量就是排名
这里不需要考虑原来加入的自己,因为按最高分加入一定比最低分加入高

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Node
{int l, r;int sum;
};
bool cmp(Node a, Node b)
{return a.sum > b.sum;
}
signed main()
{int n; scanf("%d", &n);vector<Node> vec, pre;  for(int i = 0, l, r, x, sum; i < n; i ++){scanf("%d %d", &l, &r);sum = 0;for(int j = 0; j < 5; j ++){scanf("%d", &x);sum += x;}sum += l;vec.push_back({l, r, sum});pre.push_back({l, r, sum});}sort(vec.begin(), vec.end(), cmp);vector<int> res;for(int i = 0; i < n; i ++){int sum = pre[i].sum + pre[i].r - pre[i].l;int l = 0, r = n;while(l < r){int mid = l + r >> 1;if(vec[mid].sum <= sum) r = mid;else l = mid + 1;}cout << l + 1 << '\n';}
}

G. NANA看天鹅舞会 — 贪心

最小的天鹅数黑白配对
剩下的相同2只配对
如果剩下的是奇数 减去c

#include <iostream>
using namespace std;
#define int long long
signed main()
{int n, m, a, b, c;cin >> n >> m >> a >> b >> c;if(n > m) swap(n, m);int res = n * a;m -= n;res += (m / 2) * b;if(m & 1) res -= c;cout << res << '\n';
}

H. NANA去集训 — 虚拟源点 + 堆优化的dijkstra

题目链接

这是一个很经典虚拟源点的模板题
需要将问题转化为单源最短路问题
因为最后还需要返回,因此路程距离直接乘2
对于每个答案,相当于求虚拟源点0 到点 i 的最短距离

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define int long long
const int N = 200010;
vector<pair<int, int>> g[N];
int d[N];
bool vis[N];
signed main()
{int n, m;cin >> n >> m;for(int i = 1, a, b, w; i <= m; i ++){cin >> a >> b >> w;g[a].push_back({b, w * 2});g[b].push_back({a, w * 2});}for(int i = 1, x; i <= n; i ++){cin >> x;g[0].push_back({i, x});}priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q;for(int i = 1; i <= n; i ++) d[i] = 1e18;d[0] = 0;q.push({0, 0});while(q.size()){int u = q.top().second;q.pop();if(vis[u]) continue;vis[u] = true;for(auto [v, w] : g[u]){if(d[v] > d[u] + w){d[v] = d[u] + w;q.push({d[v], v});}}}for(int i = 1; i <= n; i ++)cout << d[i] << " ";
}

I. NANA做胡辣汤 — 滑动窗口

先把处理好的全加起来
用hh记录长度为k窗口的左端点,遍历右端点每次求出长度为k的区间中的没处理好的调料数量
每次更新res

#include <iostream>
using namespace std;
const int N = 100010;
#define int long long
int a[N], b[N];
signed main()
{int n, k; cin >> n >> k;for(int i = 0; i < n; i ++) cin >> a[i];for(int i = 0; i < n; i ++) cin >> b[i];int hh = 0, sum = 0;for(int i = 0; i < n; i ++)if(b[i]) sum += a[i];// 先处理第一个窗口 for(int i = 0; i < k; i ++)if(!b[i]) sum += a[i];int res = sum;for(int i = k; i < n; i ++){if(!b[i - k]) sum -= a[i - k];if(!b[i]) sum += a[i];res = max(sum, res);}cout << res << '\n';
}

J. NANA与她的朋友们 — 双指针

题目链接

k和ai很大,但是数只有1e5个,很容易想到离散化
因为每次影响的只有最大值和最小值,就可以直接看 最大值 和 最小值分别对应的数量哪个小
每次用k减去 那个小的,维护一个双指针,直到k小于0,或者双指针相遇

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
#define int long long
map<int,int> mp;
signed main()
{int n, k, x; scanf("%lld %lld",&n, &k);vector<int> vec;for(int i = 0; i < n; i ++){scanf("%lld", &x);if(!mp.count(x)) vec.push_back(x);mp[x] ++;}sort(vec.begin(), vec.end());int hh = 0, tt = vec.size() - 1;while(hh < tt){int l = mp[vec[hh]];int r = mp[vec[tt]];if(l < r){int num = vec[hh + 1] - vec[hh];int cnt = l;if(k >= cnt * num){k -= cnt * num;mp[vec[hh + 1]] += mp[vec[hh]];hh ++;    } else{int t = k / cnt;k -= t * cnt;int res = vec[tt] - vec[hh] - t;cout << res << '\n';return 0;}}else{int num = vec[tt] - vec[tt - 1];int cnt = r;if(k >= cnt * num){k -= cnt * num;mp[vec[tt - 1]] += mp[vec[tt]];tt --;}else{int t = k / cnt;k -= t * cnt;int res = vec[tt] - t - vec[hh];cout << res << '\n';return 0;}}}cout << 0 << '\n';
}

K. NANA在郑州 — 小模拟

#include <iostream>
using namespace std;
#define int long long
int val[] = {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 4};
signed main()
{int n;cin >> n;// kong geint res = n - 1;while(n --){string s; cin >> s;for(int i = 0; i < s.size(); i ++) res += val[s[i] - 'a'];}cout << res << '\n';
}

L. NANA与梦中的洛阳 — dp

有点极限,洛谷需要开O2优化

如果问题缩减到1e6,由于y是单调不减的,dp跑一遍就好

但是现在问题是1e9的,可以考虑离散化,对于每个机关(x, y),维护y, y+1, y+2,即把这三项加入要离散化的序列中,随后跑一遍dp即可.

#include <bits/stdc++.h>using namespace std;
using ll = long long;const int N = 2e6 + 5;
const int mod = 998244353;int n, m, k;int dp[N][4], f[N][4];map<int, int> rev;int main() {//freopen("parkour3.in", "r", stdin);ios::sync_with_stdio(false), cin.tie(0);cin >> n >> m >> k;vector<pair<int, int>> res;rev[m] = 1, rev[1] = 1;for (int i = 0; i < k; i ++) {int u, v; cin >> u >> v;res.push_back({u, v});for (int j = v; j <= v + 2; j ++)rev[j] = 1;}int cnt = 0;for (auto [a, b]: rev) {rev[a] = ++ cnt;}for (auto c: res) {int a = c.first, b = c.second;f[rev[b]][a] = true;}dp[1][1] = true;int du = rev[m];for (int i = 1; i <= du; i ++) {for (int j = 1; j <= n; j ++) {if (!f[i][j])dp[i + 1][j] = (dp[i + 1][j] + dp[i][j]) % mod;else {dp[i + 1][max(1, j - 1)] = (dp[i + 1][max(1, j - 1)] + dp[i][j]) % mod;dp[min(du, i + 2)][j] = (dp[min(du, i + 2)][j] + dp[i][j]) % mod;dp[i + 1][min(n, j + 1)] = (dp[i + 1][min(n, j + 1)] + dp[i][j]) % mod;}}}for (int i = 1; i <= n; i ++)cout << dp[du][i] << '\n';return 0;
}
/*
all right,
but m8 tle?
*/

2023年 ZZU ACM 招新赛暨选拔赛题解相关推荐

  1. 2022学年第一学期郑州大学ACM招新赛选拔赛

    A SW的与众不同数组 - 签到 一共n个数, 用set无重复值的性质统计一下有几个不同的数,记为 res n - res 如果是偶数 每次删除两个刚好可以,如果是奇数需要再删除一个不重复的数完成对应 ...

  2. ACM—TC 联合招新赛 Round2

    ACM-TC 联合招新赛 Round2 A 贪心 问最少需要多少张纸币可以支付 n元 很容易可以想到 先给100元 100元用完给50 从大到小支付即可. #include <cstdio> ...

  3. 2021 CNSS招新赛 WEB WP

    前言 CNSS的一个招新赛,挺有意思的,让我感受到了校与校的差距T_T Web Signin 一开始提示Please Change Your Method!,抓包修改为POST方法即可得到源码 < ...

  4. 2022 弱口令安全实验室招新赛-靶机挑战记录

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.ubuntu 代码执行getshell 获取webshell 二.server 2008r2 EW 流量代理 ms ...

  5. [青少年CTF]弱口令实验室招新赛部分WriteUp

    Web 0x01 开胃菜 <?php highlight_file(__FILE__); if(strlen($_GET[1]&&$_GET[1]<=5)){echo st ...

  6. 20年9月wust招新赛writeup

    20年9月wust招新赛writeup Crypto 黑铁2 黑铁1 青铜3 青铜5 白银5 黄金3 黄金2 Misc 黑铁3 白银3 铂金3 黄金1 铂金2 Web 青铜2 青铜1 白银3 白银2 ...

  7. UUCTF招新赛Misc-writeup from 王八七七总结

    UUCTF(union university CTF)是由发起的联合性质新生招新赛,旨在联合更多拥有CTFer的院校共同举办联合招新等赛事,解决单独学校方向缺失以及举办招新赛减少精力等问题,联合共赢, ...

  8. SLsec招新赛wp

    文章目录 一.前言 二.题目 2.1 MISC类 2.1.1 简单的隐写 2.1.2 海贼王里的宝藏 2.1.3 找你妹啊! 2.1.4 大佬的奇妙冒险 2.1.5 简单地压缩包 2.2 CRYPTO ...

  9. 2018 焦作站亚洲区域赛校内选拔赛题解

    SUST_2018 焦作站亚洲区域赛校内选拔赛 A.高速        by yoyo tag:图论.最短路 //最短路 #include<bits/stdc++.h> using nam ...

最新文章

  1. SPP-Net 是怎么让 CNN 实现输入任意尺寸图像的?
  2. 深度学习笔记5:Building Deep Networks for Classification
  3. WebView完全解读
  4. Jackson 注解 -- 使用构造器
  5. Dockerfile文件创建centos:7,配置JDK8的环境变量,与运行springboot的jar包,的镜像
  6. python下拉菜单_自定义Django Form中choicefield下拉菜单选取数据库内容实例
  7. IOS一些常用的越狱渠道
  8. zebra代码简单分析 --- 001
  9. 某程序员自述:我,三十多岁,逃离北上广,通过技术移民到加拿大!
  10. Gxlcms有声小说系统/小说听书系统源码
  11. 原型开发工具_开发工具的未来原型
  12. C++ 04 翁恺>声明(Declarations) VS. 定义(Definitions)
  13. python爬取微博设备显示怎么更改_Python定向爬虫模拟新浪微博登录
  14. jQuery基础入门
  15. c语言程序点亮数码管,怎样点亮数码管
  16. 佩奇:Google将投入巨资开发前瞻性…
  17. [日常坑]关于linux使用vsftp搭建ftp服务器的问题
  18. linux桌面版分区,ubuntu硬盘分区方案推荐-桌面版
  19. adb connect 远程adb连接手机无法连接,显示由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。(10060)windows调试Linux解决方式 ip连接方式
  20. 互联网采集数据有哪几种常见的方法?

热门文章

  1. 通过USB在传统电视上播放B站视频
  2. Word处理控件Aspose.Words功能演示:使用 C# 将 Word 文档转换为 Markdown
  3. Windows7安装mysql-压缩包方式
  4. day23 三升序列
  5. Dbeaver连接Clickhouse无法下载/更新驱动
  6. 基于loongnix20系统,libvlc代码直接集成测试
  7. 满满的骚操作,通用流行框架大全
  8. 企业微信批量操作工具1.0
  9. 员工调职其他部门 公司百科帮大忙
  10. win10问题:无任何操作,2分钟后电脑就自动休眠