A.Three Threes(循环)
题意:
给出一个正整数NNN,要求输出NNN个NNN
分析:
按要求输出即可
代码:
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cout << n;
}
cout << endl;
}
int main() {
solve();
return 0;
}
B.Pentagon(判断)
题意:
给出正五边形上四个顶点S1,S2,T1,T2(S1≠S2,T1≠T2)S_1,S_2, T_1,T_2(S_1 \ne S_2, T_1 \ne T2)S1,S2,T1,T2(S1=S2,T1=T2),问S1S_1S1和S2S_2S2连成的线端长度与T1T_1T1和T2T_2T2之间连成的线段长度是否相等。
分析:
正五边形任意两点之间的距离分以下两种:
-
两点相邻
-
两点不相邻
判断两条线段是否属于同一类型即可。
代码:
#include <bits/stdc++.h>
using namespace std;
void solve() {
string s, t;
cin >> s >> t;
int s1 = s[0] - 'A';
int s2 = s[1] - 'A';
int t1 = t[0] - 'A';
int t2 = t[1] - 'A';
int len1 = 0, len2 = 0;
if (abs(s2 - s1) != 1 && abs(s2 - s1) != 4) len1 = 1;
if (abs(t2 - t1) != 1 && abs(t2 - t1) != 4) len2 = 1;
if (len1 == len2) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
int main() {
solve();
return 0;
}
C.Repunit Trio(预处理)
题意:
有一个序列,里面每个数字均由若干个111组成,如1,11,111,...1, 11, 111,...1,11,111,...,问任取该序列中的三个数字(每个数字可重复取)加在一起组成的所有数字中第NNN小的数字是多少?
分析:
先预处理由111组成的数字。
然后使用三场循环枚举能组成的数字。
枚举结束后排序去重,并输出第NNN小的数字即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
vector<LL> ans, num;
void solve() {
LL val = 0;
for (int i = 1; i <= 15; i++) {
val = val * 10 + 1;
num.push_back(val);
}
for (int i = 0; i <= 14; i++) {
for (int j = 0; j <= 14; j++) {
for (int k = 0; k <= 14; k++) {
ans.push_back(num[i] + num[j] + num[k]);
}
}
}
ans.push_back(0);//加个0,把存储答案的下标修改为从1开始
sort(ans.begin(), ans.end());
int len = unique(ans.begin(), ans.end()) - ans.begin();
int n;
cin >> n;
cout << ans[n] << endl;
}
int main() {
solve();
return 0;
}
D.Erase Leaves(贪心)
题意:
给出一棵树,允许进行若干次如下操作:
- 选择一个叶节点,并将该叶节点删除
问:至少需要操作多少次,才能将节点111删除。
分析:
想要让111成为叶节点,那么必然需要将1连着的边删除到只剩一条。而想要删除每一条边实际上需要将该边连接的整棵子树全部删除才行,那么最后留下的那条边连接的子树一定为111的最大子树。
以111为根节点进行遍历,记录每个节点的子树大小,最后的答案就是连接111的kkk棵子树中除最大的子树外的所有子树节点之和,再加上最后删除节点111的操作次数。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5 + 5e2;
vector<int> G[N];
int sz[N];
void dfs(int root, int pre) {
sz[root] = 1;
int len = G[root].size();
for (int i = 0; i < len; i++) {
int v = G[root][i];
if (v != pre) {
dfs(v, root);
sz[root] += sz[v];
}
}
}
vector<int> child;
void solve() {
int n;
cin >> n;
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, -1);
int len = G[1].size();
for (int i = 0; i < len; i++) {
child.push_back(sz[G[1][i]]);
}
sort(child.begin(), child.end());
int ans = 0;
for (int i = 0; i < len - 1; i++) {
ans += child[i];
}
cout << ans + 1 << endl;
}
int main() {
solve();
return 0;
}
E.Takahashi Quest(贪心)
题意:
冒险家在冒险过程中,将遇到NNN个事件。第iii个事件(1≤i≤N)(1≤i≤N)(1≤i≤N)用一对整数(ti,xi)(t_i,x_i)(ti,xi)表示(1≤ti≤2,1≤xi≤N)(1≤t_i≤2,1≤x_i≤N)(1≤ti≤2,1≤xi≤N)
每个事件的含义如下:
- 如果ti=1t_i=1ti=1,他找到了xix_ixi类型的药剂。他可以选择捡起它或丢弃它。
- 如果ti=2t_i=2ti=2,他会遇到一个xix_ixi类型的怪物。
如果他有xix_ixi类型的药剂,他可以使用一个打败怪物。如果他不打败怪物,他就会被打败。
判断他是否能够打败所有的怪物。
如果他不能打败所有的怪物,输出−1-1−1。
若可以打败所有的怪物,设KKK为他在冒险过程中所拥有的药剂的最大数量。设Kmin{K_{min}}Kmin为在冒险家采取的所有可以打败所有怪物的策略中KKK的最小值。输出KminK_{min}Kmin的值和该策略下冒险家每次找到药剂时的动作,若他捡起药剂,输出111,若他丢弃药剂,输出000。
分析:
本题采用贪心的思想,遍历事件,使用一个VectorVectorVector数组记录每种类型的药水出现的位置,并通过一个visvisvis数组记录这个位置的药水是否被使用,当需要使用药水时,由近到远遍历该种药水对应的VectorVectorVector数组中此种药水的所有位置,若没有被使用,则在visvisvis数组中将其标记为已使用,若没有未使用的药水,则表明无法满足要求,冒险家被打败。遍历NNN个事件,若该位置的药水被使用,则将手中药水数目加111,若该位置需要使用药水,则手中药水数目−1-1−1,不断更新KKK直至完全遍历。最后根据visvisvis数组输出每次找到药剂时的动作。
代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2 * 1e5;
int n;
int t[MAXN], x[MAXN], vis[MAXN];
int main() {
cin >> n;
for (int i = 0; i < n; i++)
cin >> t[i] >> x[i];
vector<vector<int>> a(n + 5);
for (int i = 0; i < n; i++) {
if (t[i] == 1) {
a[x[i]].push_back(i);
} else {
int index = a[x[i]].size() - 1;
while (index >= 0 && vis[a[x[i]][index]]) {
index--;
}
if (index < 0) {
cout << "-1" << endl;
return 0;
}
vis[a[x[i]][index]] = 1;
}
}
int ans, tmp;
ans = tmp = 0;
for (int i = 0; i < n; i++) {
if (vis[i])
tmp++;
if (t[i] == 2)
tmp--;
ans = max(ans, tmp);
}
cout << ans << endl;
for (int i = 0; i < n; i++) {
if (t[i] == 1) {
if (i == 0) {
cout << vis[i];
} else {
cout << " " << vis[i];
}
}
}
cout << endl;
return 0;
}
F.Bomb Game 2(概率DP)
题意:
有NNN个人站在一条线上,第iii个人站在第iii个位置。
重复以下操作,直到队伍中只剩下一个人:
以12\frac{1}{2}21的概率将排在队伍最前面的人移走,否则将他们移到队伍的末尾。
对于每个编号为i=1,2,…,Ni=1,2,…,Ni=1,2,…,N的人,求iii是队列中最后一个人的概率,结果对998244353998244353998244353取模。
分析:
本题为概率DP。设fi,jf_{i,j}fi,j表示长度为iii时,第jjj个的概率,以1,2,31,2,31,2,3为例,可以列出fi,1=14fi−1,2+18fi−1,1+18fi,1f_{i,1}=\frac{1}{4}f_{i-1,2}+\frac{1}{8}f_{i-1,1}+\frac{1}{8}f_{i,1}fi,1=41fi−1,2+81fi−1,1+81fi,1 ,对此式子解方程得78fi,1=14fi−1,2+18fi−1,1\frac{7}{8}f_{i,1}=\frac{1}{4}f_{i-1,2}+\frac{1}{8}f_{i-1,1}87fi,1=41fi−1,2+81fi−1,1,化简得fi,1=87(14fi−1,2+18fi−1,1)f_{i,1}=\frac{8}{7}(\frac{1}{4}f_{i-1,2}+\frac{1}{8}f_{i-1,1})fi,1=78(41fi−1,2+81fi−1,1)。
可以发现,对于fi,1f_{i,1}fi,1,其递推公式为fi,1=2i2i−1(∑j=2ifi−1,i−j+1)f_{i,1}=\frac{2^i}{2^i-1}(\sum\limits_{j=2}^{i}f_{i-1,i-j+1})fi,1=2i−12i(j=2∑ifi−1,i−j+1),使用相同方法可以推出fi,2f_{i,2}fi,2的表达式,进一步递推得出转移方程fi,j=12fi−1,j−1+12fi,j−1f_{i,j}=\frac{1}{2}f_{i-1,j-1}+\frac{1}{2}f_{i,j-1}fi,j=21fi−1,j−1+21fi,j−1
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 998244353;
const int MAXN = 3005;
LL n, F[MAXN][MAXN];
LL pow_mod(LL a, LL b, LL p) { //a的b次方求余p
LL ret = 1;
while (b) {
if (b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
int main() {
cin >> n;
F[1][1] = 1;
for (int i = 2; i <= n; i++) {
int tmp = pow_mod(2, i, MOD);
for (int j = i - 1, k = 2; j >= 1; j--, k++) {
F[i][1] = (F[i][1] + pow_mod(pow_mod(2, k, MOD), MOD - 2, MOD) * F[i - 1][j] % MOD) % MOD;
}
F[i][1] = F[i][1] * tmp % MOD * pow_mod(tmp - 1, MOD - 2, MOD) % MOD;
for (int j = 2; j <= i; j++) {
F[i][j] = (pow_mod(2, MOD - 2, MOD) * F[i - 1][j - 1] % MOD + pow_mod(2, MOD - 2, MOD) * F[i][j - 1] % MOD) % MOD;
}
}
for (int i = 1; i <= n; i++)
cout << F[n][i] << " ";
cout << endl;
return 0;
}
学习交流
以下为学习交流QQ群,群号: 546235402,每周题解完成后都会转发到群中,大家可以加群一起交流做题思路,分享做题技巧,欢迎大家的加入。

1496

被折叠的 条评论
为什么被折叠?



