A. Robot Program
如果没有限制条件的话,答案就是
n
+
m
n + m
n+m。
考虑限制条件,那么我们每走一步就要换一种走法, 很明显交替走是最优的,如果不能交替走,就停在原地。
很明显答案就是
n
+
m
+
m
a
x
(
m
a
x
(
n
,
m
)
−
m
i
n
(
n
,
m
)
−
1
,
0
)
n + m + max(max(n, m) - min(n, m) - 1, 0)
n+m+max(max(n,m)−min(n,m)−1,0)
AC代码:
#include <bits/stdc++.h>
using namespace std;
signed main()
{
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int t;
cin >> t;
while(t--)
{
int n, m;
cin >> n >> m;
cout << n + m + max(max(n, m) - 1 - min(n, m), 0) << '\n';
}
}
B. Toy Blocks
观察可得重要性质:放置完后,总积木数一定能被
m
o
d
(
n
−
1
)
mod (n - 1)
mod(n−1)。
这个性质无法推过第三个样例,所以取最大值覆盖下所有的积木盒子,然后两者取更大值。
AC代码:
#include <bits/stdc++.h>
using namespace std;
signed main()
{
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
long long sum = 0, ans = 0;
int max_val = 0;
vector <int> a(n);
for(int i = 0; i < n; ++i)
{
cin >> a[i];
sum += a[i];
max_val = max(max_val, a[i]);
if(sum % (n - 1) != 0)
ans = (sum / (n - 1) + 1) * (n - 1);
else
ans = sum;
}
ans = max(ans, 1ll * max_val * (n - 1));
ans -= sum;
cout << ans << '\n';
}
}
C. Two Brackets
贪心匹配最近的括号
AC代码:
#include <bits/stdc++.h>
using namespace std;
signed main()
{
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int t;
cin >> t;
while(t--)
{
string s;
cin >> s;
int ans = 0;
bool ok = 0;
int len = (int) s.size();
for(int l = 0, r = 0; l < len; ++l)
{
if(s[l] == '(')
{
r = max(r, l);
while(++ r < len)
{
if(s[r] == ')')
{
ans ++;
break;
}
}
}
}
for(int l = 0, r = 0; l < len; ++l)
{
if(s[l] == '[')
{
r = max(r, l);
while(++ r < len)
{
if(s[r] == ']')
{
ans ++;
break;
}
}
}
}
cout << ans << '\n';
}
}
D. Radio Towers
考虑到最初情况
n
=
1
n = 1
n=1时, 合法方案数是
1
1
1。
我们手推几组样例,发现 合法方案数是为一个斐波那契数列。
根据概率的定义:
P ( A ) = m n P(A)= \frac{m}{n} P(A)=nm
可得答案即为:
a
n
s
=
f
n
−
2
+
f
n
−
1
2
n
ans = \frac{f_{n - 2} + f_{n - 1}}{2 ^ n}
ans=2nfn−2+fn−1
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int P = 998244353;
long long ksm(long long a, int b)
{
long long res = 1;
while(b)
{
if(b & 1)
res = res * a % P;
a = a * a % P;
b >>= 1;
}
return res;
}
signed main()
{
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int n;
cin >> n;
vector <long long> v(n + 5);
v[1] = v[2] = 1;
for(int i = 3; i <= n; ++i)
{
v[i] = (v[i - 1] + v[i - 2]) % P;
}
cout << v[n] * ksm(ksm(2, n), P - 2) % P << '\n';
}
E. Two Editorials
考虑暴力枚举区间长度
k
k
k,做一个前缀和后缀。
前缀代表:老师A讲课到
i
i
i 学生最大的贡献。
后缀代表:老师B讲课到
j
j
j 学生最大的贡献。
考虑贪心策略,以每个学生区间值的中点排序,然后进行枚举即可。
时间复杂度大概是
Θ
(
n
2
)
\Theta(n^2)
Θ(n2)。
AC代码:
#include <bits/stdc++.h>
using namespace std;
struct stu
{
int l, r;
}s[(int) 2e3 + 5];
bool cmp(stu a, stu b)
{
return a.l + a.r < b.l + b.r;
}
signed main()
{
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int n, m, k;
cin >> n >> m >> k;
for(int i = 1; i <= m; ++i)
{
cin >> s[i].l >> s[i].r;
}
sort(s + 1, s + 1 + m, cmp);
vector <int> pre(m + 5, 0), suf(m + 5, 0);
for(int l = 1; l <= n - k + 1; ++l)
{
int L = l;
int R = l + k - 1;
int res1 = 0;
for(int i = 1; i <= m; ++i)
{
if(R < s[i].l || L > s[i].r)
{
pre[i] = max(pre[i], res1);
continue;
}
L = max(L, s[i].l);
R = min(R, s[i].r);
res1 += R - L + 1;
pre[i] = max(pre[i], res1);
L = l;
R = l + k - 1;
}
int res2 = 0;
for(int i = m; i >= 1; --i)
{
if(R < s[i].l || L > s[i].r)
{
suf[i] = max(suf[i], res2);
continue;
}
L = max(L, s[i].l);
R = min(R, s[i].r);
res2 += R - L + 1;
suf[i] = max(suf[i], res2);
L = l;
R = l + k - 1;
}
}
int max_val = 0;
for(int i = 1; i <= m; ++i)
{
max_val = max(max_val, pre[i] + suf[i + 1]);
}
cout << max_val << '\n';
}