题目
前言
云宝学长出题出的挺好的,我是云宝学长的粉丝啊,但是没有直播露脸题解差评。
主播这次写的有点抽象了各种唐氏操作下文会给你们看乐子的。
A 谁是老二
题面样例
< < <
输出:
B
签到题,主播选择直接列出情况
#include<bits/stdc++.h>
using namespace std;
signed main(){
cin.tie(0);
cout.tie(0);
char sa,sb,sc;
cin>>sa>>sb>>sc;
char ans;
if((sa=='<'&&sc=='<')||(sa=='>'&&sc=='>')){
ans='B';
}
if(sa=='>'&&sc=='<'){
if(sb=='>'){
ans='C';
}else{
ans='A';
}
}
if(sa=='<'&&sc=='>'){
if(sb=='<'){
ans='C';
}else{
ans='A';
}
}
cout<<ans;
}
纯粹的逻辑判断,a>b>c或者a<b<c只需判断sa,sc即可
a>c&&b>c或者a<c&&b<c得出ac之间小的就行。
B MieMieMie
c语言模板
#include <stdio.h>
char s[200005];
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
scanf("%s", s);
// 在此继续编写后续内容
}
return 0;
}
c++模板
#include <bits/stdc++.h>
int main(){
int T; std :: cin >> T;
while (T--) {
int n; std :: string s;
std :: cin >> n >> s;
// 在此继续编写后续内容
}
return 0;
}
py模板
for _ in range(int(input())):
n = int(input())
s = input()
# 在此继续编写后续内容
Output:
输出共 T 行,每行两个整数,分别表示羊的数量和披着羊皮的狼的数量。
输入样例:
6
1
M
2
Mi
3
Mie
6
MIEMie
9
MieMieMie
12
mIEmIemieMIe
输出:
0 0
0 0
1 0
1 1
3 0
0 0
使用最简单的判断字符串,判断的字符串段所以主播没用任何字符串函数直接判断了。
#include <bits/stdc++.h>
int main(){
int T; std :: cin >> T;
while (T--) {
int n; std :: string s;
std :: cin >> n >> s;
int cnt1=0,cnt2=0;
for(int i=0;i<n;i++){
if (i + 2 >= n) break;
if(s[i]=='M'){
if(s[i+1]=='I'&&s[i+2]=='E'){
cnt2++;
}
if(s[i+1]=='i'&&s[i+2]=='e'){
cnt1++;
}
}
}
std::cout<<cnt1<<" "<<cnt2<<'\n';
// 在此继续编写后续内容
}
return 0;
}
或者使用云宝学长更简单的字符串函数。
#include <bits/stdc++.h>
int main(){
int T; std :: cin >> T;
while (T--) {
int n; std :: string s;
std :: cin >> n >> s;
int A = 0, B = 0;
for (int i = 0; i < n; i++) {
if (i + 2 >= n) break;
std :: string op = s.substr(i, 3);
if (op == "Mie") A += 1;
if (op == "MIE") B += 1;
}
std :: cout << A << ' ' << B << '\n'
// 在此继续编写后续内容
}
return 0;
}
C LilaS 的颜色树
样例:
入1:
6
2 7 1 8 2 8
1 2
3 6
3 2
4 3
2 5
出1
1
2
3
4
6
入2
10
3 1 4 1 5 9 2 6 5 3
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
出2
1
2
3
5
6
7
8
本题可以直接dfs深搜,对于每个颜色开visit数组判断即可
出现+1回溯-1,千万不要写成判断每个颜色是否出现过,一路上会有颜色重复出现。
赛时主播因为这个原因没写出来,令人痛心。
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define endl '\n'
using namespace std;
void solve() {
int n;
cin >> n;
int se[100010] = { 0 };
for (int i = 1; i <= n; i++) {
cin >> se[i];
}
vector g(n + 1, vector<int>());
for (int i = 1; i < n; i++) {//邻接表存树
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
map<int, int>vi;
set <int>a;
auto dfs = [&](auto&& self, int x, int fa)->void {
if (vi[se[x]] == 0) {//没有这个颜色塞进去
a.insert(x);
}
vi[se[x]]++;//这个颜色的数量增加
for (auto tt : g[x]) {//递归
if(tt!=fa){
self(self, tt, x);
}
}
vi[se[x]] --;//回溯消除
};
dfs(dfs, 1, -1);
for(auto tt:a){
cout<<tt<<endl;
}
}
signed main() {
cin.tie(0);
cout.tie(0);
solve();
}
D RainbowDash 的旅行
样例:
入1
2 3
1 0 1
0 1 1
出1
18
入2
1 1
0
0
出2
0
本题是某种dp,虽然你不知道什么时候在哪个岛上,但是你可以把两个岛路径数量存下来,后续使用即可,
在dp过程中我们可以对岛对岛进行dp,dp数组开二维,记录到某个岛的方案数,dp[n][j]为第n - 1天到第 i 间木屋的方案数 × f[i][j] 之和,i是上一层的每个岛,j是这一层的某个岛,n为天数,dp[n][j]存入的就是上一层每个岛到这个岛的方案数,注意全过程取模,否则longlong爆炸的时候,你的提交也会爆炸。
a类桥走了怎么走都行,b类桥走了只能走a类
f[i][j]=a[i] * (a[j] + b[j])+ b[i] * a[j]是这么个说法
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define endl '\n'
using namespace std;
void solve() {
int n, m;
int a[105] = { 0 };
int b[105] = { 0 };
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> a[i];
}
for (int i = 1; i <= m; i++) {
cin >> b[i];
}
int fang[105][105];
for (int i = 1; i <= m; i++) {//计算ij的方案数
for (int j = 1; j <= m; j++) {
fang[i][j] = (a[i] * (a[j] + b[j])%mod + b[i] * a[j]%mod)%mod;
}
}
vector dp(n + 1, vector<int>(m + 1));
dp[0][1] = 1;
for (int p = 1; p <= n; p++) {//第n天
for (int i = 1; i <= m; i++) {//下层岛屿
for (int j = 1; j <= m; j++){//上层岛屿
dp[p][i] = (dp[p][i] + dp[p - 1][j] * fang[j][i]%mod)%mod;
}
}
}
int ans = 0;
for (int i = 1; i <= m; i++) {
ans =(ans+ dp[n][i])%mod;
}
cout << ans << endl;
}
signed main() {
cin.tie(0);
cout.tie(0);
solve();
}
E 简单路径计数
样例
入1
4 2
1 2
2 3
出1
3
入2
4 6
1 2
1 3
1 4
2 3
2 4
3 4
出2
16
本题主要是搜索和剪枝,剪枝在哪里呢,题面的10^6,大于的全剪掉就好,在这里是主播的第二次唐氏,没看到剪枝条件,就打了最基础的最短剪枝就交了,果不其然,炸了,主播出于对自己计数的不自信,直接跑路换题了。赛后小改一下就完成了。
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define endl '\n'
using namespace std;
void solve() {
int N = 1000000; // 最大路径数上限
int n, m;
cin >> n >> m;
int vi[1005] = {0}; // 顶点访问标记
int cnt = 0; // 路径计数器
vector<vector<int>> g(n + 1); // 邻接表
// 输入边并构建邻接表
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
// DFS遍历所有简单路径
auto dfs = [&](auto&& self, int x, int fa) -> void {
if (vi[x]) return; // 已访问则跳过(避免重复顶点)
vi[x] = 1; // 标记当前顶点为已访问
cnt++; // 每进入一个新顶点,路径数+1
if (cnt >= N) { // 若超过上限则提前终止
vi[x] = 0;
return;
}
// 遍历所有邻居
for (int tt : g[x]) {
if (tt != fa) { // 避免回到父节点
self(self, tt, x);
if (cnt >= N) break; // 提前终止后续递归
}
}
vi[x] = 0; // 回溯,撤销访问标记
};
dfs(dfs, 1, -1); // 从顶点1开始,父节点初始为-1
cout << min(cnt, N) << endl; // 输出结果
}
signed main() {
cin.tie(0);
cout.tie(0);
solve();
}
F RainbowDash 的数字游戏
样例
入
7
1
2
3
19
22
28
85
出
1 1
1 2
2 1
4 3
1 7
7 1
7 7
本题是主播最蠢的一集,很简单的数学问题,最左边一列,第n行是n个数的等差数列的和
直接就是(n^2+n)/2,每个数x肯定是小于这一斜行的最大的数,小于上一行的最大,直接可以找到斜行,然后根据头数和x的差直接算出x的坐标,
本题的图应该是这样的,很正常,但是主播看题面的矩形就产生了多余的想法
大家看题记得一定读好题,不用像主播一样变成糖b。
本题我用数学做法,记得注意精度问题。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
void solve() {
const int N=500000000500000000;
const int T=1000000000;
int n;
cin>>n;
int flag=0;
// cout<<n;
int xx=(sqrtl(8*n+1)-1)/2;
int sum=xx*(xx+1)/2;
int po=xx;
if(sum<n){
po++;
}
long long cha;
cha=po*(po+1)/2-n;
if(flag==0){
cout<<po-cha<<" "<<1+cha<<endl;
}else{
cout<<T-(po-cha)+1<<" "<<T-(1+cha)+1<<endl;
}
}
signed main() {
cin.tie(0);
cout.tie(0);
int _;
cin>>_;
while(_--)solve();
}
另附云宝学长二分做法
#include <bits/stdc++.h>
using LL = long long;
int main() {
int T; std :: cin >> T;
while (T--) {
LL n; std :: cin >> n;
LL lo = 0, hi = 1e10, k = -1;
while (lo <= hi) {
LL mid = (lo + hi) / 2;
LL sum = (1 + mid) * mid / 2;
if (sum < n) k = mid, lo = mid + 1;
else hi = mid - 1;
}
LL t = (1 + k) * k / 2;
LL x = n - t, y = k + 1 - n + t + 1;
std :: cout << x << ' ' << y << '\n';
}
return 0;
}
G LilaS 的抛硬币
样例
入1
3
1 3
3 1
2 2
出1
2 3 1
第 1 个人的运气是 0.25 ,第 2 个人的运气是 0.75 ,第 3 个人的运气是 0.5 。
按运气从高到低排序即可得到答案。
入2
2
1 3
2 6
出2
1 2
请注意, 1 和 2 应按编号升序打印,因为它们的运气相同。
入3
4
999999999 1000000000
333333333 999999999
1000000000 999999997
999999998 1000000000
出3
3 1 4 2
本题我开了个结构体,存概率和编号,直接sort能过,属于较为方便的做法。
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define endl '\n'
using namespace std;
struct aa{
double date;
int po;
};
bool cmp(aa x,aa y){
if(x.date==y.date){
return x.po<y.po;
}
return x.date >y.date;
}
void solve() {
int n;
cin>>n;
aa gg[1005];
for(int i=0;i<n;i++){
double a,b;
cin>>a>>b;
double tmp=a/(a+b);
gg[i].date=tmp;
gg[i].po=i+1;
}
sort(gg,gg+n,cmp);
for(int i=0;i<n;i++){
cout<<gg[i].po<<" ";
}
}
signed main() {
cin.tie(0);
cout.tie(0);
solve();
}
H RainbowDash 的 Robot
这个等主播学完线段树什么的再说();
在此附上云宝学长的解。
样例
入1
11 10
9 0 0 10 3 4 8 11 10 8
6
1 2 1 3 1
1 2 1 3 2
4 3 4 5 2
5 3 11 5 3
5 3 11 5 2
11 9 9 10 1
出1
Yes
No
No
No
Yes
Yes
解
#include <bits/stdc++.h>
const int N = 2e5 + 10;
class node {
public:
int L, R, mx;
}s[4 * N];
int a[N];
int n, m, q;
void build(int k, int L, int R) {
s[k] = { L, R, a[L] };
if (L == R) return;
int mid = L + R >> 1;
build(k << 1, L, mid);
build(k << 1 | 1, mid + 1, R);
s[k].mx = std::max(s[k << 1].mx, s[k << 1 | 1].mx);
return;
}
int query(int k, int L, int R) {
if (s[k].L >= L && s[k].R <= R)
return s[k].mx;
int mid = s[k].L + s[k].R >> 1;
int res = 0;
if (L <= mid) res = std::max(res, query(k << 1, L, R));
if (R > mid) res = std::max(res, query(k << 1 | 1, L, R));
return res;
}
int main() {
std::cin >> n >> m;
for (int i = 1; i <= m; i++) std::cin >> a[i];
build(1, 1, m);
std::cin >> q;
while (q--) {
int xs, ys, xf, yf, t;
std::cin >> xs >> ys >> xf >> yf >> t;
if (xs % t != xf % t || ys % t != yf % t) {
std::cout << "No\n";
continue;
}
int Q = query(1, std::min(ys, yf), std::max(ys, yf));
int tar = (n - xs) / t * t + xs;
std::cout << (Q < tar ? "Yes\n" : "No\n");
}
return 0;
}
I LilaS 的逻辑表达式
样例:
入1
2
AND
OR
出1
5
带点结论性质,选手是这样的,只需要算01就行,位运算要考虑的事情就多了。
与运算的话若第i项为1则前面一定全是1,如果为0答案不可能是1;
或运算的话如果后面出现了1则这一项这么填都行,如果没有则状态转移到i-1判断;
综上只需要考虑或运算就好如果这一项是或则直接加pow(2,i);
反向走就行
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int qpow (int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = res * a;
b >>= 1;
a = a * a;
} return res;
}
void solve() {
int n;
cin >> n;
int zhi[66] = { 0 };
for (int i = 1; i <= n; i++) {
string a;
cin >> a;
if (a[0] == 'O') {
zhi[i] = 0;
}
if(a[0]=='A'){
zhi[i]=1;
}
}
int ans = 1;
for (int i = n; i >= 1; i--) {
if(zhi[i])continue;
ans += qpow(2ll, i);
}
cout << ans;
}
signed main() {
cin.tie(0);
cout.tie(0);
solve();
}
云宝学长说不用快速幂也能写,但是注意不要用pow,因为我没对,还是快速幂吧。
J 数字转换大师
样例
入1
12
出1
1-643-2-346-1
入2
7
出2
17777771
入3
1
出3
11
模拟直接扫就行。
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define endl '\n'
using namespace std;
void solve() {
int n;
cin >> n;
for (int i = 0; i <= n; i++) {
int flag = 0;
for (int j = 1; j <= 9; j++) {
if (n % j != 0) continue;
int t = n / j;
if (i % t == 0) {
flag = 1;
cout << j;
break;
}
}
if (flag == 0) {
cout << "-";
}
}
}
signed main() {
//ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
solve();
}
K LilaS的特殊图判断
样例:
入1
3 3
2 3
1 1
2 3
出1
Yes
入2
13 16
7 9
7 11
3 8
1 13
11 11
6 11
8 13
2 11
3 3
8 12
9 11
1 11
5 13
3 12
6 9
1 10
出2
No
本题是搜索,打dfs找连通块,注意的一点,样例一就有的,一个点可以连自己,一条边统计两个点,看点的数量是不是边的两倍就行,实际写出来多少费点功夫,走一遍搜索搜出来连通块是哪几个点会标注释
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
vector<vector<int>> g(n + 1); // 邻接表存储图
vector<int> in(n + 1); // 记录每个顶点的度数
// 读取边并构建邻接表和度数数组
for (int i = 0; i < m; i++) {
int x, y;
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
in[x]++; // 每个顶点的度数增加
in[y]++;
}
int kua = 0; // 连通块计数器
vector<int> kuai(n + 1); // 记录每个顶点所属的连通块编号
vector<int> vi(n + 1); // 访问标记数组
// DFS遍历,标记连通块
auto dfs = [&](auto&& self, int x) -> void {
vi[x] = 1; // 标记为已访问
kuai[x] = kua; // 记录当前顶点所属连通块
for (auto tt : g[x]) {
if (vi[tt]) continue; // 跳过已访问的顶点
self(self, tt); // 递归遍历邻接顶点
}
};
// 遍历所有顶点,划分连通块
for (int i = 1; i <= n; i++) {
if (!vi[i]) {
kua++; // 新的连通块编号
dfs(dfs, i); // 遍历该连通块
}
}
// ans数组存储每个连通块的顶点数(first)和总度数(second)
vector<pair<int, int>> ans(kua + 1);
for (int i = 1; i <= n; i++) {
ans[kuai[i]].first++; // 统计连通块顶点数
ans[kuai[i]].second += in[i]; // 累加总度数
}
int flag = 0;
// 检查每个连通块是否满足条件:顶点数 * 2 == 总度数
// 总度数 = 2 * 边数,所以顶点数 == 边数 等价于顶点数 * 2 == 总度数
for (int i = 1; i <= kua; i++) {
if (ans[i].first * 2 != ans[i].second) {
flag = 1;
cout << "No"; // 不满足条件,直接输出No
return;
}
}
// 所有连通块均满足条件
cout << "Yes";
}
signed main() {
cin.tie(0);
cout.tie(0);
solve();
}
注释有点地狱,找ai了一下(),感觉deepseek比豆包加的科学一点。
L LilaS 与数字交换
树状数组也没学,先附云宝学长的解();
样例
入1
3
1 2 3
3 1 2
出1
Yes
入2
5
1 2 3 4 5
3 4 5 1 2
出2
Yes
入3
8
1 2 3 4 5 6 7 8
7 8 5 6 4 3 1 2
出3
No
入4
3
1 1 2
2 1 1
出4
Yes
入5
3
1 1 1
2 2 2
出5
No
解1树状数组解
#include <bits/stdc++.h>
using LL = long long;
const int N = 2e5 + 10;
int a[N], b[N], s[N], ca[N], cb[N];
void add (int i) {
for (; i <= 200000; i += (i & -i))
s[i] += 1;
return;
}
LL query (int i) {
LL res = 0;
for (; i >= 1; i -= (i & -i))
res += s[i];
return res;
}
int main () {
int n; std :: cin >> n;
for (int i = 0; i < n; i++) std :: cin >> a[i], ca[a[i]] += 1;
for (int i = 0; i < n; i++) std :: cin >> b[i], cb[b[i]] += 1;
for (int i = 1; i <= 200000; i++) {
if (ca[i] != cb[i]) {
std :: cout << "No";
return 0;
}
}
for (int i = 1; i <= 200000; i++) {
if (ca[i] > 1) {
std :: cout << "Yes";
return 0;
}
}
LL qa = 0, qb = 0;
for (int i = n - 1; i >= 0; i--) {
qa += query(a[i] - 1);
add(a[i]);
}
for (int i = 0; i < N; i++) s[i] = 0;
for (int i = n - 1; i >= 0; i--) {
qb += query(b[i] - 1);
add(b[i]);
}
if ((qa & 1) == (qb & 1)) std :: cout << "Yes";
else std :: cout << "No";
return 0;
}
解2模拟解
#include <bits/stdc++.h>
const int N = 2e5 + 10;
int va[N], vb[N], ca[N], cb[N];
std :: vector <std :: set <int>> sa(N), sb(N);
std :: vector <int> a, b;
int main () {
int n; std :: cin >> n;
for (int i = 0; i < n; i++) std :: cin >> va[i], ca[va[i]] += 1;
for (int i = 0; i < n; i++) std :: cin >> vb[i], cb[vb[i]] += 1;
for (int i = 0; i < N; i++) {
if (ca[i] != cb[i]) {
std :: cout << "No";
return 0;
}
}
for (int i = 0; i < N; i++) {
if (ca[i] > 1) {
std :: cout << "Yes";
return 0;
}
}
for (int i = 0; i < n; i++) {
if (va[i] == vb[i]) continue;
a.push_back(va[i]), b.push_back(vb[i]);
}
int len = a.size();
for (int i = 0; i < len; i++) {
sa[a[i]].insert(i), sb[b[i]].insert(i);
}
for (int i = 0; i < len - 1; i++) {
if (a[i] == b[i]) {
sa[a[i]].erase(i);
sb[b[i]].erase(i);
continue;
}
int fa = -1, fb = -1;
for (int j = i + 1; j < len; j++) {
if (a[j] == b[j]) continue;
fa = j;
auto pos = sb[a[j]].lower_bound(i + 1);
if (pos != sb[a[j]].end()) {
fb = *pos;
break;
}
fa = -1, fb = j;
auto pos2 = sa[b[j]].lower_bound(i + 1);
if (pos2 != sa[b[j]].end()) {
fa = *pos2;
break;
}
}
if (fa == -1 || fb == -1) {
std :: cout << "No";
return 0;
}
sa[a[fa]].erase(fa);
sb[a[fa]].erase(fb);
sa[a[i]].erase(i);
sa[a[i]].insert(fa);
sb[b[i]].erase(i);
sb[b[i]].insert(fb);
std :: swap(a[i], a[fa]);
std :: swap(b[i], b[fb]);
}
std :: cout << "Yes";
return 0;
}
模拟等有时间了试试,有点窒息。
M RainbowDash 的整除问题
样例
入
5
10 4
13 9
100 13
123 456
92 46
出
2
5
4
333
0
考虑余数,b减去ab的余数就是a和b的倍数的差,如18%5=3,5-3=2,18+2=20,就是5的倍数,最后记得再模一次b,整除的时候要直接输出0而不是b,最后模一次会修正。
当然如果a<b,可以直接输出两者之差,但是没什么意义;
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define endl '\n'
using namespace std;
void solve() {
int a, b;
cin >> a>>b;
cout << (b - a % b)%b << endl;
}
signed main() {
cin.tie(0);
cout.tie(0);
int _;
cin >> _;
while (_--) {
solve();
}
}
总结
这次就开了五个题,赛后好奇为什么都不会写,当晚补了赛时看过的三个,
补完直接睡不着了,直通早上六点
总体来说这次主播除了树状数组线段树什么的没学之外,问题主要在于cef这三个,c题的计数出错直接怂了,e变成瞎子怂了,e没怂,也是没去再看看题,
成傻子了 ,赛时心态有点小问题,经常怀疑是自己技术有问题,也不愿意去看看是不是题读的有问题,主播可能是人,但是主播写的像人不太可能
难度评分应该是这样的
Easy A、B、G、J、M
Mid C、E、F、I、K
Hard D、H、L
主播硬生生做成
Easy A、B、G、J、M
Mid I、K
Hard D、H、L、C、E、F、
牢骚当作没看到
这次排名也是低的离谱了,写题有点缺乏自信,以及代码容易出现瑕疵,不止需要写题,赛时和平常差别还是极大的,主播因为比赛心态被人喷小学生 ,总的来说还是比赛写少了。