2021 年东北林业大学 ACM 校赛题解
A - 前进东北林业大学
#include <stdio.h>
int main(){puts("203");}
B - 病毒传播
假如我们每天传播 人,一共 个患者,那么每天增加的人数就是 。
#include <iostream>
using namespace std;
using ULL = unsigned long long;
int main() {
int n, x;
cin >> x >> n;
ULL now = 1;
for (int i = 0; i < n; i++) {
now += now * x;
}
cout << now << '\n';
}
C - 语汐和她的加权成绩
#include <iostream>
#include <set>
#include <vector>
using namespace std;
multiset<double, greater<double>> s;
int main() {
int n;
cin >> n;
while (n--) {
int m;
cin >> m;
double sum = 0;
double all = 0;
for (int i = 0; i < m; i++) {
double a, b;
cin >> a >> b;
sum += a * b;
all += b;
}
s.insert(sum / all);
}
for (auto x : s) {
printf("%.2f\n", x);
}
return 0;
}
D - jwgg的字符串
找到一个替换即可。
#include <iostream>
using namespace std;
int main() {
string a, b, c;
cin >> a >> b >> c;
if (a.find(b) == a.npos) {
cout << a << c << '\n';
} else {
int kki = a.find(b);
cout << a.substr(0 , kki)
<< c
<< a.substr(kki +
b.length())
<< '\n';
}
return 0;
}
E - 小A的二进制
了解一下二进制运算符,即可。
#include <iostream>
using namespace std;
int main() {
int t;
cin >> t;
while (t--) {
long long a, b;
cin >> a >> b;
int ans = 0;
for (int i = 0; i < 100; i++) {
ans += (a & 1) != (b & 1);
a >>= 1, b >>= 1;
}
cout << ans << '\n';
}
return 0;
}
或者
#include <bitset>
#include <iostream>
using namespace std;
int main() {
int t;
cin >> t;
while (t--) {
unsigned long long a, b;
cin >> a >> b;
bitset<64> s(a ^ b);
cout << s.count() << '\n';
}
}
F - 小H与小Y
根本做不上来
G - 飞,比跑快吧
我们直接看三号样例吧。
我们每次飞行都有若干次降落和上升组成,并且这些动作是紧紧挨着的。
那么也就可以换成一次下降+一次上升,或者一次上升和一次下降。
那么选择哪个呢?
如果先下降后上升,难免会产生后效性,也就是说,我们的最低点有可能会被上升所干扰。
因此我们选择后者,那么我们每次将未落地的部分先处理完再处理最后一部分即可。
#include <cmath>
#include <iostream>
using namespace std;
int main() {
// ios::sync_with_stdio(false);
// cin.tie(0);
int t;
cin >> t;
while (t--) {
int a, b, x, y;
// cin >> a >> b >> x >> y;
scanf("%d%d%d%d", &a, &b, &x, &y);
int times = y / 8;
double havx = times * 9.0 * b / a;
bool ans = false;
if (havx >= x)
ans = true;
else if (times * 8 == y)
;
else {
havx = x - havx;
double havy = y - times * 8;
havy += 1;
if (b * havy >= a * havx ||
fabs(b * havy - a * havx) <= 1e-8)
ans = true;
}
if (ans)
puts("yes");
else
puts("no");
}
return 0;
}
H - 油豆腐和八重子。
想法还么有完全证明出来,看看出题人怎么证明的。
看代码自然就懂啦~~。
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
using LL = long long;
vector<LL> A(2 * n + 1);
for (int i = 1; i <= n; i++) cin >> A[i];
for (int i = n + 1; i <= 2 * n; i++) A[i] = A[i - n];
if (k == 1) {
cout << A[1] << '\n';
return 0;
}
LL ans = -1;
LL sum = A[1];
for (int i = 2; i <= 2 * n; i++) {
sum += A[i];
if (i <= k) {
LL tmp = k - i;
if (tmp & 1) {
tmp = tmp / 2 * A[i] +
(tmp / 2 + 1) * A[i - 1];
} else {
tmp = tmp / 2 * (A[i] + A[i - 1]);
}
ans = max(ans, sum + tmp);
}
}
A[0] = A[1];
reverse(A.begin() + 1, A.end());
for (int i = 2 * n; i > 0; i--) A[i] = A[i - 1];
sum = A[1];
for (int i = 2; i <= 2 * n; i++) {
sum += A[i];
if (i <= k) {
LL tmp = k - i;
if (tmp & 1) {
tmp = tmp / 2 * A[i] +
(tmp / 2 + 1) * A[i - 1];
} else {
tmp = tmp / 2 * (A[i] + A[i - 1]);
}
ans = max(ans, sum + tmp);
}
}
cout << ans << '\n';
}
I - 你什么时候来啊,我的甘雨!
我们从一到十的二进制表示如下
/*
* 0 :
* 1 : 1
* 2 : 10
* 3 : 11
* 4 : 100
* 5 : 101
* 6 : 110
* 7 : 111
* 8 : 1000
* 9 : 1001
*/
显然高位需要尽可能的大,低位需要尽可能的宽,尽可能的小。那么因此高位填 9 ,低位填 8
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
for (int i = n; i >= 1; i--)
if ((i - 1) * 4 + 1 <= n) putchar('8');
else putchar('9');
puts("");
}
}
J - 刻晴和她的烤吃虎鱼
我们只要遵循生鱼先烤的原则即可保证我们的答案符合最优,然后暴力即可。
#include <iostream>
using namespace std;
int main() {
int t;
cin >> t;
while (t--) {
long long n, m, k;
cin >> n >> m >> k;
long long fresh, cooked;
fresh = cooked = 0;
long long ans;
long long lasted;
for (ans = 60;; ans += 15) {
lasted = min(n, fresh);
fresh -= lasted;
cooked += lasted;
if (n - lasted) {
lasted = min(n - lasted, cooked - lasted);
cooked -= lasted;
}
if (ans % 60 == 0) {
lasted = min(k, m * 2);
k -= lasted;
fresh += lasted;
}
if (k == 0 && fresh == 0 && cooked == 0) break;
}
cout << ans << '\n';
}
return 0;
}
K - 数数
我们不难发现这个只是一个插空法。全部排上 1 然后插入 0 即可。
- 时
- 时
由于组合数的特征,不难发现有
那么也就变为斐波那契数列了,
我们再看看首项为2,第二项为 3。
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
const int MOD = 19260817;
long long Fib[N];
int main() {
int t;
cin >> t;
Fib[0] = 1;
Fib[1] = 2;
for (int i = 2; i < N; i++) Fib[i] = (Fib[i - 1] + Fib[i - 2]) % MOD;
while (t--) {
int n;
scanf("%d", &n);
res = Fib[n];
printf("%lld\n", res);
}
return 0;
}
L - 语汐与小哥哥
我们采用贪心的原则,首先按从小到大的顺序排序,然后从大到小填数,使他们每个人的总分尽可能的最小。然后,对于每个人我们也按照贪心的原则,让他加上最大的值,如果比之前的最小总分的最大值大的话,那么这个人就有可能成为TA的对象。
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<long long> v(n);
for (int i = 0; i < n; i++) scanf("%lld", &v[i]);
sort(begin(v), end(v));
long long maxx = -1;
for (int i = 0; i < n; i++) {
maxx = max(maxx, v[i] + n - i);
}
int res = 0;
for (int i = 0; i < n; i++) {
if (v[i] + n >= maxx) res++;
}
cout << res << '\n';
return 0;
}