A. 输出字符
给定一个长度为 l e n len len 的数字串,补全前缀零,使得输出串长度为 4 4 4
#include<bits/stdc++.h>
using namespace std;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
string s;
cin >> s;
for (int i = 0; i < 4 - (int) s.size(); i++) {
cout << '0';
}
cout << s << endl;
return 0;
}
B. 简单统计
给定数组 a a a 和数 p p p,统计 a a a 中有多少个数 < p <p <p
循环一边即可
复杂度: O ( N ) O(N) O(N)
#include<bits/stdc++.h>
using namespace std;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, p, x, cnt = 0;
cin >> n >> p;
for (int i = 1; i <= n; i++) {
cin >> x;
cnt += x < p;
}
cout << cnt << endl;
return 0;
}
C. 模拟
需要记录当前所有人的状态,即 ( x , p ) (x, p) (x,p), x x x 表示标号为 p p p 的人当前的分数
每次需要进行排序,以 x x x 降序,如果 x x x 相等,按 p p p 增序,模拟一遍过程即可
#include<bits/stdc++.h>
using namespace std;
string a[110];
int ans[110];
bool cmp(pair<int, int> a, pair<int, int> b) {
if (a.first == b.first) return a.second < b.second;
else return a.first > b.first;
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, m;
vector<pair<int, int>> vt;
cin >> n >> m;
for (int i = 0; i < n * 2; i++) {
cin >> a[i];
vt.push_back({0, i});
}
for (int i = 0; i < m; i++) {
sort(vt.begin(), vt.end(), cmp);
for (int j = 0; j < n; j++) {
int p1 = vt[2 * j].second, p2 = vt[2 * j + 1].second;
char cha = a[p1][i], chb = a[p2][i];
if (cha == chb) {
continue;
}
else {
string v;
v += cha; v += chb;
if (v == "GC" || v == "CP" || v == "PG"){
vt[2 * j].first++;
}
else {
vt[2 * j + 1].first++;
}
}
}
}
sort(vt.begin(), vt.end(), cmp);
for (auto it: vt) {
cout << it.second + 1 << endl;
}
return 0;
}
D. 动态规划
很容易容易想到一个 d p dp dp
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 个数,最后一个数取到的值为 j j j,所有满足条件的总情况数
那么有以下转移:
- d p [ i ] [ j ] ← ∑ k = 1 j d p [ i − 1 ] [ k ] dp[i][j]\leftarrow \sum\limits_{k = 1}^{j}dp[i - 1][k] dp[i][j]←k=1∑jdp[i−1][k]
那么显然总复杂度是: O ( N M 2 ) O(NM^2) O(NM2),其中 M = max A , B M = \max {A, B} M=maxA,B
这里 ∑ k = 1 j d p [ i − 1 ] [ k ] \sum\limits_{k = 1}^{j}dp[i - 1][k] k=1∑jdp[i−1][k] 是前缀和的形式,我们把 d p [ i ] [ j ] dp[i][j] dp[i][j] 重新定义为前缀和的形式就可以 O ( 1 ) O(1) O(1) 转移了
那么转移变为 d p [ i ] [ j ] ← d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j] \leftarrow dp[i - 1][j] + dp[i][j - 1] dp[i][j]←dp[i−1][j]+dp[i][j−1]
#include<bits/stdc++.h>
using namespace std;
const int N = 3e3 + 5, mod = 998244353;
int dp[N][N], a[N], b[N];
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
fill(dp[0], dp[0] + N, 1);
for (int i = 1; i <= n; i++) {
for (int j = a[i]; j <= b[i]; j++) {
dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % mod;
}
for (int j = b[i] + 1; j < N; j++) {
dp[i][j] = dp[i][j - 1];
}
}
cout << dp[n][N - 1] << endl;
return 0;
}
E. dfs 求路径 + dp
首先我们需要对于每条边,这条边被走过了多少次
我们可以 M M M 次 dfs, O ( N M ) O(NM) O(NM) 次的复杂度来求得
比如现在我们知道了每条边经过了多少次,计入 v v v 数组中, ∣ v ∣ = N − 1 |v| = N - 1 ∣v∣=N−1
那么每条边图成蓝色意味着权值为 + 1 +1 +1,否则权值为 − 1 -1 −1
现在需要给这 N − 1 N - 1 N−1 个数分配 + 1 +1 +1 或 − 1 -1 −1 的权值,来使得和为 K K K,我们需要知道有多少种分配方式
每条路径的贡献是最多是 N − 1 N - 1 N−1 那么 M M M 次贡献最多是 ( N − 1 ) M (N - 1)M (N−1)M,那么有 ∑ v ≤ ( N − 1 ) M \sum\limits v \leq (N - 1)M ∑v≤(N−1)M
我们可以知道这 N − 1 N - 1 N−1 个数通过加上 + 1 +1 +1 或 − 1 -1 −1 的权值之后最大表示的范围是 [ − ( N − 1 ) M , ( N − 1 ) M ] [-(N - 1)M, (N - 1)M] [−(N−1)M,(N−1)M]
那么我们可以 d p dp dp 来求所有可能的值以及情况数了
这个过程和 D D D 题很像
考虑到真实情况是非常稀疏的,所以可以考虑用 m a p map map 来转移(事实上确实跑得比较快)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5, mod = 998244353;
int n, m, k, fg;
vector<int> nxt[N];
int a[N];
map<pair<int, int>, int> cnt;
vector<int> path, ans;
map<int, int> pre, now;
void dfs(int now, int fa, int to) {
path.push_back(now);
if (now == to) {
ans = path;
return;
}
for (auto it: nxt[now]) {
if (it == fa) continue;
dfs(it, now, to);
}
path.pop_back();
}
void solve(int x, int y) {
fg = 0;
path.clear();
ans.clear();
dfs(x, -1, y);
for (int i = 1; i < (int) ans.size(); i++) {
int u = ans[i - 1], v = ans[i];
cnt[{u, v}]++;
cnt[{v, u}]++;
}
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m >> k;
for (int i = 1; i <= m; i++) {
cin >> a[i];
}
for (int i = 1, u, v; i < n; i++) {
cin >> u >> v;
nxt[u].push_back(v);
nxt[v].push_back(u);
}
for (int i = 1; i < m; i++) {
solve(a[i], a[i + 1]);
}
vector<int> vv;
for (int i = 1; i <= n; i++) {
for (auto it: nxt[i]) {
if (it > i) vv.push_back(cnt[{i, it}]);
}
}
// for (auto it: vv) {
// cout << it << " ";
// }
// cout << endl;
now[0] = 1;
for (auto val: vv) {
pre = now;
now.clear();
for (auto it: pre) {
now[it.first - val] += pre[it.first];
now[it.first - val] %= mod;
now[it.first + val] += pre[it.first];
now[it.first + val] %= mod;
}
}
cout << (now[k] + mod) % mod << endl;
return 0;
}