2022年浙大城市学院新生程序设计竞赛(同步赛)
A. OP (Nowcoder48876 A)
题目大意
输出fengqibisheng, yingyueerlai!
解题思路
python最快
我错了,php
直接打这个字符串就可以了
神奇的代码
print("fengqibisheng, yingyueerlai!")
B. Steel of Heart (Nowcoder48876 B)
题目大意
一个打怪模拟题
解题思路
按照题意模拟即可,用数组维护被动生效时间。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T, typename... rest>
void read(T &x, rest&... Rest) {
read(x);
read(Rest...);
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int la[6];
int main(void) {
LL h1, h2;
int n;
read(h1, h2, n);
for(int i = 0; i < 6; ++ i)
la[i] = -2000;
bool own = false;
auto calc = [](LL x){
long long qwq = floor((125 + 1.0 * x * 0.06) * 0.1);
return qwq;
};
for(int i = 1; i <= n; ++ i){
int m, s, k;
scanf("%d:%d", &m, &s);
int t = m * 60 + s;
read(k);
if (k == 1){
h1 += 800;
own = true;
}else if (k == 2){
h1 += h2;
}else{
int target;
read(target);
if (own && t - la[target] >= 30){
h1 += calc(h1);
la[target] = t;
}
}
}
write(h1, '\n');
return 0;
}
C. Add 9 Zeros (Nowcoder48876 C)
题目大意
给定\(n\)个数字\(a_i\),问 \(a_i + 9\)不是这\(n\)个数的个数。
解题思路
拿map
或set
记录下出现的数即可。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
set<int> qwq;
int n;
cin >> n;
for(int i = 1; i <= n; ++ i){
int x;
cin >> x;
qwq.insert(x);
}
set<int> qaq;
for(auto i : qwq){
if (qwq.find(i + 9) == qwq.end())
qaq.insert(i + 9);
}
cout << qaq.size() << '\n';
return 0;
}
D. Cutting with Lines Ⅰ (Nowcoder48876 D)
题目大意
<++>
解题思路
<++>
神奇的代码
E. Cutting with Lines Ⅱ (Nowcoder48876 E)
题目大意
<++>
解题思路
<++>
神奇的代码
F. Survivor (Nowcoder48876 F)
题目大意
\(n\)名玩家,第 \(i\)名玩家初始 \(a_i\)血,每分钟扣 \(b_i\)血,对其实施回复魔法,一次回复 \(c_i\)血。
现你可以实施不超过\(k\)次恢复魔法,问 \(m\)分钟后存活玩家的最大数量。玩家血量小于等于0即死亡。
解题思路
预处理让第\(i\)名玩家在 \(m\)分钟后存活的最少实施回复魔法次数数组 \(cnt_i\),从小到大依次恢复直到超过 \(k\)。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
LL m, k;
cin >> n >> m >> k;
vector<LL> a(n), b(n), c(n), cnt(n);
for(auto &i : a)
cin >> i;
for(auto &i : b)
cin >> i;
for(auto &i : c)
cin >> i;
for(int i = 0; i < n; ++ i){
a[i] -= m * b[i];
if (a[i] <= 0){
cnt[i] = (-a[i] + 1 + c[i] - 1) / c[i];
}else {
cnt[i] = 0;
}
}
sort(cnt.begin(), cnt.end());
int ans = 0;
while(ans < n){
if (k - cnt[ans] >= 0){
k -= cnt[ans];
++ ans;
}else
break;
}
cout << ans << endl;
return 0;
}
G. Red Black Tree (Nowcoder48876 G)
题目大意
给定一个直角等腰三角形摆放的格子,初始状态下一些格子颜色为黑色。其余为红色。现在要求将最小数量的红色格子变成黑色,满足以下两个要求:
- 黑色格子\((i,j)\)的下面两个格子 \((i + 1, j), (i + 1, j + 1)\) 颜色也必须是黑色
- 两个相邻黑色格子\((i,j), (i, j + 1)\)的上一个格子\((i - 1, j)\)颜色也必须是黑色
问黑色格子数量的最小值。
解题思路
不考虑第二个条件的话,同一列考虑最上面(行号最小)的黑色格子,最终局面就是一些黑色直角等腰三角形的叠加。
加上第二个条件的话,造成的额外影响就是,两个相互覆盖的黑色直角三角形会融合,变成一个更大的直角等腰三角形。
模拟该过程统计答案即可。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 1e6 + 8;
int maxx[N];
int yy[N], cnt;
LL calc(int n){
return 1ll * n * (n + 1) / 2;
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, k;
cin >> n >> k;
for(int i = 1; i <= k; ++ i){
int x, y;
cin >> x >> y;
++ cnt;
yy[cnt] = y;
maxx[y] = max(maxx[y], n - x + y + 1);
}
sort(yy + 1, yy + 1 + cnt);
cnt = unique(yy + 1, yy + 1 + cnt) - yy - 1;
int l = yy[1];
int r = maxx[yy[1]];
LL ans = 0;
for(int i = 2; i <= cnt; ++ i){
if (r >= yy[i]){
r = max(r, maxx[yy[i]]);
}else{
ans += calc(r - l);
l = yy[i];
r = maxx[yy[i]];
}
}
ans += calc(r - l);
cout << ans << '\n';
return 0;
}
H. Beautiful String (Nowcoder48876 H)
题目大意
给定一个字符串\(s\),求满足以下任意条件之一的长度为 \(n\)的各位互不相同的字符串 \(t\)的数量
- 串\(t\)从左到右的字母的字典序依次增大,且 \(t_1\)(第一个字母)在 \(s\)出现过
- 串\(t\)中的字母在串 \(s\)都出现过。
注意串 \(s\)和串 \(t\)都由英文前\(18\)位小写字母组成。
解题思路
考虑满足第一个条件的字符串个数。
枚举第一个字母,其在\(s\)出现过,假设是第\(i\)个英文字母,则剩下位数的方案数就是 \(\tbinom{18-i}{n-1}\)
考虑满足第二个条件的字母串个数,假设\(s\)串出现了 \(m\)种字母,个数就是\(\tbinom{m}{n} \times n!\)(阶乘就是排列数) 。
再减去同时满足一二条件的个数,其实就是\(\tbinom{m}{n}\)
因此答案就是\(\sum_{i \in s}\tbinom{18-i}{n-1} + \tbinom{m}{n} \times (n! - 1)\)
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define FOR(i, x, y) for (decay<decltype(y)>::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay<decltype(x)>::type i = (x), _##i = (y); i > _##i; --i)
const int N = 18;
int cnt[N], n, m;
LL jie[20];
LL C(int n, int m){
if (n < m || n < 0 || m < 0)
return 0;
return jie[n] / jie[m] / jie[n - m];
}
LL A(int n, int m){
if (n < m || n < 0 || m < 0)
return 0;
return jie[n] / jie[n - m];
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
jie[0] = 1;
FOR(i, 1, N + 1)
jie[i] = jie[i - 1] * i;
int t;
cin >> t;
while(t--){
string s;
cin >> s >> n;
for(auto &i : s)
cnt[i - 'a'] ++;
LL tmp = 0;
int cc = 0;
for(int i = 0; i < N; ++ i)
if (cnt[i] != 0){
m |= (1 << i);
++ cc;
tmp += C(18 - i - 1, n - 1);
}
tmp -= C(cc, n);
tmp += A(cc, n);
cout << tmp << '\n';
for(int i = 0; i < N; ++ i)
cnt[i] = 0;
}
return 0;
}
I. Digit Problem (Nowcoder48876 I)
题目大意
已知数\(x,y\)在二进制下有 \(a\)个 \(1\), \(b\)个 \(0\),其差 \(z = x - y\)有 \(c\)个 \(1\)。
给一个可能的 \(x,y\)。不存在输出 \(-1\)
解题思路
构造题从简单入手。
考虑\(x\)和 \(y\)的所有 \(1\)都在高位,此时其\(z\)没有 \(1\)。
考虑 \(y\)的最低位的 \(1\)往低位移\(1\)位,则 \(z\)会多一个 \(1\)。
此时 \(b \geq c\)的时候可采用该方法构造。
考虑 \(b < c\)。
假设 \(z\)的 \(c\)个 \(1\)都在低位,令\(y = x - z\),可以看成 \(y = x - (z + 1) + 1\) ,相当于把\(x\)的高\(c+1\)位的 \(1\)放到最低位,\(1\)的个数和 \(x\)一样。
注意\(a=0,b=0,a+b<=c\)的特殊情况。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int a, b, c;
cin >> a >> b >> c;
if (a + b <= c || (a == 0 && c != 0) || (b == 0 && c != 0))
cout << -1 << '\n';
else{
if (b >= c){
string x(a + b, '0'), y(a + b, '0');
fill(x.begin(), x.begin() + a, '1');
if (a > 0){
fill(y.begin(), y.begin() + a - 1, '1');
y[a + c - 1] = '1';
}
cout << x << '\n';
cout << y << '\n';
}else{
string x(a + b, '0'), y(a + b, '0');
fill(x.begin(), x.begin() + a, '1');
fill(y.begin(), y.begin() + a, '1');
y[a + b - c - 1] = '0';
y.back() = '1';
cout << x << '\n';
cout << y << '\n';
}
}
return 0;
}
J. Simple Game (Nowcoder48876 J)
题目大意
\(n\)个数字,每人每回合拿走一个数字,直至无数字剩下。\(Alice\)先手, \(Bob\)后手。最后若两人拿走数的和的差是奇数, \(Alice\)A胜,否则 \(Bob\)胜。问两者绝顶聪明的情况下谁胜。
解题思路
奇偶性的相加减,也就是模\(2\)的加减其实等效于异或,即这两个操作是一样的。
因此无论他们怎么拿,最终情况都是一样,即和是奇数就\(Alice\)胜,否则 \(Bob\)胜。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
int ans = 0;
while(n--){
int x;
cin >> x;
ans ^= (x & 1);
}
if (ans)
cout << "Alice" << '\n';
else
cout << "Bob" << '\n';
return 0;
}
K. Bit (Nowcoder48876 K)
题目大意
假设当前数为\(x\),给定\(n\)个操作,操作有三种类型:
- 给定 \(a\),令\(x = x \& a\),即与运算。
- 给定 \(a\),令\(x = x | a\),即或运算。
- 给定 \(a\),令\(x = x \oplus a\),即异或运算。
有\(q\)个询问,每个询问给定一个 \(r\),要求从 \([0,r]\)中选定 一个数\(x\),使得该数经过这 \(n\)个操作后的数最大。
解题思路
注意到位运算,二进制位之间独立,因此依次考虑每个数位取值\(0\)或 \(1\)。
预处理数组\(f[i][j]\)表示第 \(i\) 位取值为\(j\)(\(0\)或 \(1\)), 经过这\(n\)次操作后变成的值。
然后就从高位开始依次考虑每位取值为 \(0\)或 \(1\)。取值过程考虑是否有最高位限制(不大过 \(r\)),就像数位 \(dp\)里的\(limit\)变量。
即当前位如果可取\(0,1\),且最终值,取 \(1\)的时候更大,那肯定取 \(1\),否则就取 \(0\)。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 1e5 + 8;
int n, q;
int f[35][2];
int op[N], num[N];
int cal(int type, int lv, int rv){
if (type == 1)
return lv & rv;
else if (type == 2)
return lv | rv;
else
return lv ^ rv;
}
int calc(int pos, int x){
for(int i = 1; i <= n; ++ i){
x = cal(op[i], ((num[i] >> pos) & 1), x);
}
return x;
}
int b[32], pos, ans[32];
void dfs(int pos, int limit){
if (pos < 0)
return;
if (limit && b[pos] == 0){
ans[pos] = 0;
dfs(pos - 1, limit && (b[pos] == 0));
}
else{
int g1 = f[pos][1];
int g0 = f[pos][0];
if (g1 > g0){
ans[pos] = 1;
dfs(pos - 1, limit && (b[pos] == 1));
}else{
ans[pos] = 0;
dfs(pos - 1, limit && (b[pos] == 0));
}
}
}
void solve(int r){
pos = -1;
while(r){
++ pos;
b[pos] = (r & 1);
r >>= 1;
}
dfs(pos, 1);
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> q;
for(int i = 1; i <= n; ++ i){
cin >> op[i] >> num[i];
}
for(int i = 0; i < 30; ++ i){
f[i][0] = calc(i, 0);
f[i][1] = calc(i, 1);
}
while(q--){
int r;
cin >> r;
solve(r);
int val = 0;
for(int i = 0; i <= pos; ++ i){
if (ans[i])
val |= (1 << i);
}
cout << val << '\n';
}
return 0;
}
L. Elden Ring (Nowcoder48876 L)
题目大意
\(2n\)个人, 各\(n\)个人围城一个环共两个环。从\(1\)和 \(n+1\)人从 \(1\)报数,报到\(m\)的倍数的两人交换位置。问报到\(k\)时的局面。
解题思路
\(k\)不大,按题意模拟即可。
神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
vector<int> a(n), b(n);
iota(a.begin(), a.end(), 1);
iota(b.begin(), b.end(), n + 1);
int m, k;
cin >> m >> k;
int pos = 0;
int cnt = m;
for(int i = 1; i <= k; ++ i){
-- cnt;
if (cnt == 0){
swap(a[pos], b[pos]);
cnt = m;
}
++ pos;
if (pos == n)
pos = 0;
}
for(int i = 0; i < n; ++ i)
cout << a[i] << ' ';
for(int i = 0; i < n; ++ i)
cout << b[i] << ' ';
return 0;
}