[A - Hell, World!](A - Hell, World!)
难度:入门;标签:字符串
题目大意
在字符串HelloWold中,删除第 个字符并输出。
具体思路
代码实现
时间复杂度:;空间复杂度:
#include <bits/stdc++.h>using namespace std;#define ll long long#define cll const long long#define ull unsigned long long#define db double#define MAX LLONG_MAX#define MIN LLONG_MIN#define pb push_back#define pp pop_back()#define pr pair<ll, ll>#define fir first#define sec secondcll N = 1e5 + 10;ll x;void solve(){ string s = "HelloWorld"; cin >> x; for(ll i = 0;i < 10;i++) if(i != x - 1) cout << s[i];}int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); ll T = 1; // cin >> T; while(T--) solve(); return 0;}[B - 459](B - 459)
难度:入门;标签:字符串、模拟
题目大意
有 个字符串(后文称 ),取 的首字母,把他转变成 。 根据以下信息转变:
- 若 的首字符为 a, b, c 之一,则 。
- 若 的首字符为 d, e, f 之一,则 。
- 若 的首字符为 g, h, i 之一,则 。
- 若 的首字符为 j, k, l 之一,则 。
- 若 的首字符为 m, n, o 之一,则 。
- 若 的首字符为 p, q, r, s 之一,则 。
- 若 的首字符为 t, u, v 之一,则 。
- 若 的首字符为 w, x, y, z 之一,则 。
最后连接 ,输出即可。
具体思路
这道题也很简单,只需循坏遍历每一个字符串,取首字母判断输出就行了
代码实现
时间复杂度;空间复杂度:
#include <bits/stdc++.h>using namespace std;#define ll long long#define cll const long long#define ull unsigned long long#define db double#define MAX LLONG_MAX#define MIN LLONG_MIN#define pb push_back#define pp pop_back()#define pr pair<ll, ll>#define fir first#define sec secondcll N = 1e5 + 10;ll n;void solve(){ cin >> n; for(ll i = 1;i <= n;i++){ string s; cin >> s; s = "0" + s; if(s[1] == 'a' || s[1] == 'b' || s[1] == 'c') cout << 2; else if(s[1] == 'd' || s[1] == 'e' || s[1] == 'f') cout << 3; else if(s[1] == 'g' || s[1] == 'h' || s[1] == 'i') cout << 4; else if(s[1] == 'j' || s[1] == 'k' || s[1] == 'l') cout << 5; else if(s[1] == 'm' || s[1] == 'n' || s[1] == 'o') cout << 6; else if(s[1] == 'p' || s[1] == 'q' || s[1] == 'r' || s[1] == 's') cout << 7; else if(s[1] == 't' || s[1] == 'u' || s[1] == 'v') cout << 8; else cout << 9; }}int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); ll T = 1; // cin >> T; while(T--) solve(); return 0;}[C - Drop Blocks](C - Drop Blocks)
难度:普及/提高-;标签:模拟
题目大意
给你 个单元格,最开始每个单元格都没有积木。 一共有两种操作:
1 x:将一个图块放入第 个单元格中。如果每个单元格都有1个积木,则让所有单元格的数量减一。2 y:查询所有单元格中积木数大于 个的单元格数量并输出。
具体思路
这道题如果用数组去存每一个单元格中积木数量,那么时间复杂度为 (因为每个操作都需要 O(N)去做)。
由于 ,肯定会超时,所以我们引入一个新的STL容器哈希表,这里我用的是unordered_map,不知道的看这里。
这里我为了更快处理操作1,引入了懒标记(就是先不做操作,等要用的时候再更新)。
代码实现
时间复杂度:;空间复杂度:
#include <bits/stdc++.h>using namespace std;#define ll long long#define cll const long long#define ull unsigned long long#define db double#define MAX LLONG_MAX#define MIN LLONG_MIN#define pb push_back#define pp pop_back()#define pr pair<ll, ll>#define fir first#define sec secondcll N = 3e5 + 10;ll n, q, cha, a[N];unordered_map<ll, ll>sum;void solve(){ cin >> n >> q; sum[0] = n; while(q--){ ll op; cin >> op; if(op == 1){ ll x; cin >> x; sum[a[x]]--; if(!sum[a[x]]) sum.erase(a[x]); a[x]++; sum[a[x]]++; if(!sum.count(cha)) cha++; }else{ ll y; cin >> y; ll ans = 0; for(auto &[num, cnt] : sum) if(num - cha >= y) ans += cnt; cout << ans << "\n"; } }}int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); ll T = 1; // cin >> T; while(T--) solve(); return 0;}这时候有人就要问了,为什么操作2没超时呢。 我们来进行《一点点》数学推导。 首先由于 。 我要们最大限度利用数字,所以公式为 如果 。 则列出一元二次方程: 所有该方程有解并有两个根,根据求根公式,得: 则 由于积木数大于等于0,则保留 ,所以哈希表内最多有765个数字。 则操作2需要的时间复杂度为 所以不用担心超时。
[D - Adjacent Distinct String](D - Adjacent Distinct String)
难度:普及/提高-;标签:字符串、贪心
题目大意
给你一个字符串,在字符串的全排列里找出一种方法使得 。
具体思路
首先我们可以想到一种构造方式为xyxy...xyx,也就是我们拿最多的和第二多的进行排列。如果除了最多的字符没有其他字符了,那就证明不合法。我们可以用priority_queue(优先队列)来实时更新。
代码实现
时间复杂度:;空间复杂度:
#include <bits/stdc++.h>using namespace std;#define ll long long#define cll const long long#define ull unsigned long long#define db double#define MAX LLONG_MAX#define MIN LLONG_MIN#define pb push_back#define pp pop_back()#define pr pair<ll, ll>#define fir first#define sec secondcll N = 3e5 + 10;string s;void solve(){ cin >> s; string ans; ll sum[30]; memset(sum, 0, sizeof sum); for(char &e : s) sum[e - 'a']++; priority_queue<pr>q; for(ll i = 0;i < 26;i++) if(sum[i] != 0) q.push({sum[i], i}); while(q.size()){ auto [num1, c1] = q.top(); q.pop(); if(num1 == 1 || ans.back() == char(c1 + 'a')){ ans.pb(char(c1 + 'a')); continue; } if(!q.size()){ cout << "No\n"; return; } auto [num2, c2] = q.top(); q.pop(); ans.pb(char(c1 + 'a')); ans.pb(char(c2 + 'a')); q.push({num1 - 1, c1}); if(num2 > 1) q.push({num2 - 1, c2}); } cout << "Yes\n"; cout << ans << "\n";}int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); ll T = 1; cin >> T; while(T--) solve(); return 0;}[E - Select from Subtrees](E - Select from Subtrees)
难度:普及+/提高;标签:树形DP、拓扑排序、组合数学
题目大意
给你一颗根为1的树,第 个节点的父亲是 ,第 个节点上有 个糖果,第 只松鼠要拿 颗糖果,松鼠取的糖果要从是他的子树拿,且第 只松鼠在第 个节点上,问你松鼠选择糖果的方案数对 取模是多少。
具体思路
根据题面我们就知道第 松鼠要从 颗糖果中取 颗,很明显这就是组合数学中的组合数,公式为:。
由于题目中要取模,且998244353为质数,则可以使用逆元的知识,公式为 ,则公式可化简为:。
我们可以设 为 , 为 (逆元)。很明显根据 ,。
那 怎么求呢?我们可以根据逆元的性质 则 ,得 。我们用 数组表示,就是 。再根据逆元的性质:,我们在两边同时乘上 ,得 。也就是 。
然后我们该如何遍历呢?由于我的注意力惊人,发现在叶子节点的松鼠,根本不受干扰,然后他的父亲就等于他的孩子剩余糖果和加上自己的所在节点的糖果,进行组合数计算就行了。这很像拓扑排序的思想。
然后这道题就写完了
代码实现
时间复杂度:;空间复杂度:
#include <bits/stdc++.h>using namespace std;#define ll long long#define cll const long long#define ull unsigned long long#define db double#define MAX LLONG_MAX#define MIN LLONG_MIN#define pb push_back#define pp pop_back()#define pr pair<ll, ll>#define fir first#define sec secondcll N = 3e6 + 10, M = 2e5 + 10, mod = 998244353;ll n, p[M], deg[M], c[M], d[M], ans = 1, num[M], deg2[M];vector<ll> fact(N), inv(N);ll qpow(ll a, ll b) { ll res = 1; while (b > 0) { if (b % 2 == 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res;}void init() { fact[0] = 1; for (ll i = 1; i < N; i++) fact[i] = fact[i - 1] * i % mod; inv[N-1] = qpow(fact[N - 1], mod - 2); for (ll i = N-2; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod;}ll C(ll n, ll k){ if (k < 0 || k > n) return 0; ll res = 1; for (ll i = 0; i < k; i++) res = res * ((n - i) % mod) % mod; return res * inv[k] % mod;}void solve(){ cin >> n; for(ll i = 2;i <= n;i++){ cin >> p[i]; deg[p[i]]++; } for(ll i = 1;i <= n;i++) cin >> c[i], num[i] = c[i]; for(ll i = 1;i <= n;i++) cin >> d[i]; queue<ll>q; for(ll i = 1;i <= n;i++){ if(deg[i] == 0) q.push(i); } while(q.size()){ ll u = q.front(); q.pop(); if(C(num[u], d[u]) == 0){ cout << 0; return; } ans = ans % mod * C(num[u], d[u]); if(u == 1) continue; num[p[u]] += (num[u] - d[u]); deg[p[u]]--; if(deg[p[u]] == 0) q.push(p[u]); } cout << ans % mod << "\n";}int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); init(); ll T = 1; // cin >> T; while(T--) solve(); return 0;}