本文主要是介绍SDNU_LqbTraining_2022_1【解题报告】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
戳我进入比赛
Problem A. Edge Checker
题意
在一个长度为 10 10 10 的环上,给出两个点 a a a 和 b b b,问点 a a a 和点 b b b 是否相邻.
1 ≤ a ≤ b ≤ 10 1 \leq a \leq b \leq 10 1≤a≤b≤10.
分析
点 a a a 与点 b b b 相邻等价于点 a a a 是点 b b b 的后继点或者点 b b b 是点 a a a 的后继点.
即 b % 10 + 1 = a b\%10+1=a b%10+1=a 或 a % 10 + 1 = b a\%10+1=b a%10+1=b.
时间复杂度 O ( 1 ) O(1) O(1),空间复杂度 O ( 1 ) O(1) O(1).
代码
#include <bits/stdc++.h>
using namespace std;void work() {int a, b; scanf("%d %d", &a, &b);puts(a % 10 + 1 == b || b % 10 + 1 == a ? "Yes" : "No");
}int main() {work();return 0;
}
Problem B. Count Distinct Integers
题意
给出长度为 n n n 的整数序列 a [ 1.. n ] a[1..n] a[1..n],问序列 a a a 中不同元素有多少个.
1 ≤ n ≤ 1 0 3 , 1 ≤ a i ≤ 1 0 9 1 \leq n \leq 10^3, 1 \leq a_i \leq 10^9 1≤n≤103,1≤ai≤109.
分析
这题怎么做都行,比如:
- sort + O(n) 扫一遍判断相邻数是否相同
- sort + unique
- set
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn).
PS:unique是什🐎?
代码
#include <bits/stdc++.h>
using namespace std;const int M = (int)1e3;int n, a[M + 5];void work() {scanf("%d", &n);for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);sort(a + 1, a + n + 1);printf("%lu\n", unique(a + 1, a + n + 1) - (a + 1));
}int main() {work();return 0;
}
Problem C. Jumping Takahashi
题意
在数轴上,小 T 初始站在原点.
接下来走 n n n 步,第 i i i 步小 T 可以选择朝数轴正方向走 a i a_i ai 或者 b i b_i bi.
问 n n n 步之后,小 T T T 能否走到 x x x.
1 ≤ n , a i , b i ≤ 1 0 2 , 1 ≤ x ≤ 1 0 4 1 \leq n,a_i,b_i \leq 10^2,1 \leq x \leq 10^4 1≤n,ai,bi≤102,1≤x≤104.
分析
dp 裸体.
记 f [ i ] [ j ] f[i][j] f[i][j] 表示小 T T T 走 i i i 步之后能否到达 j j j.
则有转移方程 f [ i ] [ j ] = f [ i − 1 ] [ j − a i ] ∣ f [ i − 1 ] [ j − b i ] f[i][j] = f[i-1][j-a_i]|f[i-1][j-b_i] f[i][j]=f[i−1][j−ai]∣f[i−1][j−bi].
最后只需要判断 f [ n ] [ x ] f[n][x] f[n][x] 是否为 1 1 1.
时间复杂度 O ( n x ) O(nx) O(nx),空间复杂度 O ( n x ) O(nx) O(nx).
代码
#include <bits/stdc++.h>
using namespace std;const int M = (int)1e2;
const int N = (int)1e4;bool f[M + 5][N + 5];void work() {int n, x; scanf("%d %d", &n, &x);f[0][0] = 1;for(int i = 1, a, b; i <= n; ++i) {scanf("%d %d", &a, &b);for(int j = 0; j <= x; ++j) if(f[i - 1][j]) {if(j + a <= x) f[i][j + a] = 1;if(j + b <= x) f[i][j + b] = 1;}}puts(f[n][x] ? "Yes" : "No");
}int main() {work();return 0;
}
Problem D. Strange Balls
题意
有 n n n 个球,第 i i i 个球上标记着一个数字 a i a_i ai.
把这 n n n 个球顺序放入栈中,每当有 a a a 个标着数字 a a a 的球相邻时,这 a a a 个球便会消失.
问每次放球操作后,栈中球的个数.
1 ≤ n ≤ 2 × 1 0 5 , 2 ≤ a i ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5, 2 \leq a_i \leq 2 \times 10^5 1≤n≤2×105,2≤ai≤2×105.
分析
维护一个栈,存放的是数字 a a a 和数字 a a a 的连续个数.
每次放球只需要更新栈顶即可.
详见代码.
时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n).
代码
#include <bits/stdc++.h>
using namespace std;stack<pair<int, int>> st;void work() {int n; scanf("%d", &n);for(int i = 1, a, ans = 0; i <= n; ++i) {scanf("%d", &a);++ans;if(st.empty()) st.push(make_pair(a, 1));else {if(st.top().first == a) {pair<int, int> p = st.top(); st.pop();p.second++;if(p.first != p.second) st.push(p);else ans -= p.first;} else st.push(make_pair(a, 1));}printf("%d\n", ans);}
}int main() {work();return 0;
}
Problem E. Ranges on Tree
题意
给一颗 n n n 的点的有根树,根为 1 1 1.
记 s i s_i si 表示 i i i 号点的子树点集.
要求构造 n n n 个区间 [ l i , r i ] [l_i,r_i] [li,ri],满足:
- 若 s i ⊆ s j s_i \subseteq s_j si⊆sj,则 [ l i , r i ] ⊆ [ l j , r j ] [l_i,r_i] \subseteq [l_j,r_j] [li,ri]⊆[lj,rj].
- 若 s i ⋂ s j = ∅ s_i \bigcap s_j = \emptyset si⋂sj=∅,则 [ l i , r i ] ⋂ [ l j , r j ] = ∅ [l_i,r_i] \bigcap [l_j,r_j] = \emptyset [li,ri]⋂[lj,rj]=∅.
- 最小化 m a x { l 1 , l 2 , ⋯ , l n , r 1 , r 2 , ⋯ , r n } max\{l_1,l_2,\cdots,l_n,r_1,r_2,\cdots,r_n\} max{l1,l2,⋯,ln,r1,r2,⋯,rn}.
2 ≤ n ≤ 2 × 1 0 5 2 \leq n \leq 2 \times 10^5 2≤n≤2×105.
分析
手模一下样例可以发现 [ l i , r i ] [l_i,r_i] [li,ri] 选择 s i s_i si 的叶子编号即可.
时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n).
代码
#include <bits/stdc++.h>
using namespace std;const int M = (int)2e5;
const int inf = 0x3f3f3f3f;int n;
vector<int> g[M + 5];
int l[M + 5], r[M + 5], cnt;void dfs(int u, int fa) {for(const int& v: g[u]) {if(v == fa) continue;dfs(v, u);l[u] = min(l[u], l[v]);r[u] = max(r[u], r[v]);}if(l[u] == inf) l[u] = r[u] = ++cnt;
}void work() {scanf("%d", &n);for(int i = 1; i <= n; ++i) l[i] = inf, r[i] = -inf;for(int i = 2, u, v; i <= n; ++i) {scanf("%d %d", &u, &v);g[u].push_back(v);g[v].push_back(u);}dfs(1, 0);for(int i = 1; i <= n; ++i) printf("%d %d\n", l[i], r[i]);
}int main() {work();return 0;
}
Problem F. Madoka and Math Dad
题意
T T T 组输入,每组输入给一个整数 n n n.
要求构造一个数 x x x,满足:
- x x x 的数位之和为 n n n
- x x x 相邻两个数位上的数互异
- x x x 最大.
1 ≤ T , n ≤ 1 0 3 1 \leq T,n \leq 10^3 1≤T,n≤103.
分析
显然, x x x 的数位上用 1 1 1 和 2 2 2 间隔填充最优.
手模一下样例可以发现 x x x 的构成与 n % 3 n\%3 n%3 有关,按照规律写一下就完啦.
时间复杂度 O ( T n ) O(Tn) O(Tn),空间复杂度 O ( 1 ) O(1) O(1).
代码
#include <bits/stdc++.h>
using namespace std;void work() {int n; scanf("%d", &n);if(n % 3 == 1) printf("1");for(int i = 0; i < n / 3; ++i) printf("21");if(n % 3 == 2) printf("2");printf("\n");
}int main() {int T; scanf("%d", &T);while(T--) work();return 0;
}
Problem G. Madoka and the Elegant Gift
题意
T T T 组输入,每组输入给一个大小为 n × m n \times m n×m 的 01 01 01 矩阵.
定义一个子矩阵 A A A 是好的,当且仅当 A A A 只包含 1 1 1 且 A A A 不被另一个全 1 1 1 矩阵包含.
要求判断是否存在两个不同的好矩阵相交.
1 ≤ T ≤ 2 × 1 0 2 , 1 ≤ n , m ≤ 1 0 2 , ∑ n , ∑ m ≤ 777 1 \leq T \leq 2 \times 10^2, 1 \leq n,m \leq 10^2, \sum{n},\sum{m} \leq 777 1≤T≤2×102,1≤n,m≤102,∑n,∑m≤777.
分析
画一下图其实可以发现,只需要判断是否存在一下四种情况即可:
时间复杂度 O ( ∑ n m ) O(\sum{nm}) O(∑nm),空间复杂度 O ( ∑ n m ) O(\sum{nm}) O(∑nm).
代码
#include <bits/stdc++.h>
using namespace std;const int M = (int)1e2;int n, m;
char s[M + 5][M + 5];int dx[] = {1, 1, -1, -1};
int dy[] = {1, -1, 1, -1};void work() {scanf("%d %d", &n, &m);for(int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);for(int i = 1; i <= n; ++i) {for(int j = 1; j <= m; ++j) if(s[i][j] == '1') {for(int k = 0; k < 4; ++k) {int x = i - dx[k], y = j - dy[k];if(x < 0 || x > n || y < 0 || y > m) continue;if(s[x][j] == '1' && s[i][y] == '1' && s[x][y] == '0') return printf("NO\n"), void();}}}printf("YES\n");
}int main() {int T; scanf("%d", &T);while(T--) work();return 0;
}
Problem H. Madoka and Childish Pranks
题意
T 组输入,每组输入给一个大小为 n × m n \times m n×m 的 01 01 01 矩阵 B B B.
初始有一个大小为 n × m n \times m n×m 的全 0 0 0 矩阵 A A A,每次操作可以选一个 A A A 的子矩阵进行棋盘染色.
问若干次操作之后,能否把 A A A 变为 B B B,若能则输出方案.
1 ≤ T ≤ 10 , 1 ≤ n , m ≤ 1 0 2 1 \leq T \leq 10, 1 \leq n,m \leq 10^2 1≤T≤10,1≤n,m≤102.
分析
通过对 ( x , y − 1 ) (x,y-1) (x,y−1) 到 ( x , y ) (x,y) (x,y) 进行棋盘染色,我们可以把矩阵 A A A 的第 2 2 2 列到第 m m m 列染成想要的任意样子.
再考虑第 1 1 1 列,通过对 ( x , y ) (x,y) (x,y) 到 ( x − 1 , y ) (x-1,y) (x−1,y) 进行棋盘染色,我们可以把矩阵 A A A 第一列的第 2 2 2 行到第 n n n 行染成想要的任意样子.
因此无解等价于 B [ 1 ] [ 1 ] = 1 B[1][1]=1 B[1][1]=1.
时间复杂度 O ( ∑ n m ) O(\sum{nm}) O(∑nm),空间复杂度 O ( ∑ n m ) O(\sum{nm}) O(∑nm).
代码
#include <bits/stdc++.h>
using namespace std;const int M = (int)1e2;int n, m;
char s[M + 5][M + 5];
vector<pair<pair<int, int>, pair<int, int>>> ans;void work() {ans.clear();scanf("%d %d", &n, &m);for(int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);if(s[1][1] == '1') return printf("-1\n"), void();for(int i = 1; i <= n; ++i) {for(int j = m; j >= 2; --j) if(s[i][j] == '1') {ans.push_back(make_pair(make_pair(i, j - 1), make_pair(i, j)));s[i][j] = '0';}}for(int i = n; i >= 2; --i) if(s[i][1] == '1') {ans.push_back(make_pair(make_pair(i - 1, 1), make_pair(i, 1)));s[i][1] = '0';}int n = (int)ans.size();printf("%d\n", n);for(int i = 0; i < n; ++i) printf("%d %d %d %d\n", ans[i].first.first, ans[i].first.second, ans[i].second.first, ans[i].second.second);
}int main() {int T; scanf("%d", &T);while(T--) work();return 0;
}
Problem I. Madoka and the Best School in Russia
题意
T T T 组输入,每组输入两个整数 x x x 和 d d d.
定义:
- 一个数是 good 当且仅当它是 d d d 的倍数
- 一个数是 beatiful 当且仅当它是 good 且它不能被表示成两个 good 数之积
现给出 good 数 x x x,问 x x x 能否表示成至少两种不同的方式(若干个 beatiful 数之积).
1 ≤ t ≤ 1 0 2 , 2 ≤ x , d ≤ 1 0 9 1 \leq t \leq 10^2,2 \leq x,d \leq 10^9 1≤t≤102,2≤x,d≤109.
分析
先来看几个性质
性质一:一个数 a a a 是 good 当且仅当 d ∣ a d \mid a d∣a.
性质二:一个数 a a a 是 beatiful 当且仅当 d ∣ a d\mid a d∣a 且 d 2 ∤ a d^2 \nmid a d2∤a.
证明:
先证必要性
设两个 good 数 n 1 = k 1 d , n 2 = k 2 d n_1=k_1d,\,n_2=k_2d n1=k1d,n2=k2d.
由 a ≠ n 1 n 2 a\not=n_1n_2 a=n1n2 可得 a ≠ k 1 k 2 d 2 a\not=k_1k_2d^2 a=k1k2d2.
即 a a a 不可以表示成 k × d 2 k\times d^2 k×d2 的形式.
因此 d 2 ∤ a d^2 \nmid a d2∤a.
懒得证充分性.
性质三:一个 good 数 x x x 是 beatiful,则 x x x 一定无法表示成两种不同的方式(若干个 beatiful 数之积).
证明:
beatiful 数 x x x 只有一种表示方式,即 x x x.
因此 good 数 x x x 能够表示成两种不同的方式(若干个 beatiful 数之积),必须要满足 d 2 ∣ x d^2 \mid x d2∣x.
分解 x x x 得到 x = k d × d c ( k , d ) = 1 x=kd \times d^c \,\, (k,d)=1 x=kd×dc(k,d)=1.
显然有第一种方案: x = k d × d × ⋯ × d ⏟ c 个 d x=kd \times \underbrace{d \times \cdots \times d}_{c个d} x=kd×c个d d×⋯×d.
另外的方案则是去考虑 k k k 能否拆分或者最后一个 d d d 能否拆分.
时间复杂度 O ( ∑ d ) O(\sum{\sqrt{d}}) O(∑d),空间复杂度 O ( 1 ) O(1) O(1).
代码
#include <bits/stdc++.h>
using namespace std;typedef long long ll;bool is_prime(int n) {if(n == 1) return 0;for(int i = 2; (ll)i * i <= n; ++i) if(n % i == 0) return 0;return 1;
}void work() {ll x, d; scanf("%lld %lld", &x, &d);if(x % (d * d)) return printf("NO\n"), void();ll k = x / d, c = 0;while(k % d == 0) k /= d, ++c;if((c >= 3 && !is_prime(d)) || (k > 1 && !is_prime(k))) return printf("YES\n"), void();if(c == 1 || is_prime(d)) return printf("NO\n"), void();for(int i = 2; (ll)i * i <= d; ++i) if(d % i == 0) {if(k * i % d || k * d / i % d) return printf("YES\n"), void();}printf("NO\n");
}int main() {int T; scanf("%d", &T);while(T--) work();return 0;
}
Problem J. Nearest Excluded Points
题意
二维平面上有 n n n 个互异整数点 ( x i , y i ) (x_i,y_i) (xi,yi),对每个点求出一个曼哈顿距离最近点 ( x , y ) (x,y) (x,y),满足 ( x , y ) (x,y) (x,y) 不在那 n n n 个点当中.
1 ≤ n , x i , y i ≤ 2 × 1 0 5 1 \leq n,x_i,y_i \leq 2 \times 10^5 1≤n,xi,yi≤2×105.
分析
对 n n n 个点的每个点向上下左右连边,做一个超级源反向 bfs 即可.
代码
#include <bits/stdc++.h>
using namespace std;const int M = (int)2e5;int n, m;
int x[M + 5], y[M + 5];
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
set<pair<int, int>> vis;
set<pair<int, int>> st[2];
map<pair<int, int>, pair<int, int>> res;void work() {scanf("%d", &n); m = 0;for(int i = 1; i <= n; ++i) {scanf("%d %d", &x[i], &y[i]);st[0].insert(make_pair(x[i], y[i]));for(int j = 0; j < 4; ++j) st[0].insert(make_pair(x[i] + dx[j], y[i] + dy[j])), st[1].insert(make_pair(x[i] + dx[j], y[i] + dy[j]));}for(int i = 1; i <= n; ++i) st[1].erase(make_pair(x[i], y[i]));queue<pair<int, int>> q;for(set<pair<int, int>>::iterator i = st[1].begin(); i != st[1].end(); ++i) {q.push(*i);vis.insert(*i);res[*i] = *i;}while(!q.empty()) {pair<int, int> u = q.front(); q.pop();for(int i = 0; i < 4; ++i) {pair<int, int> v = u;v.first += dx[i], v.second += dy[i];if(st[0].count(v) && !res.count(v)) {res[v] = res[u];q.push(v);}}}for(int i = 1; i <= n; ++i) {pair<int, int> p = res[make_pair(x[i], y[i])];printf("%d %d\n", p.first, p.second);}
}int main() {work();return 0;
}
这篇关于SDNU_LqbTraining_2022_1【解题报告】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!