AtCoder Beginner Contest 243
A
直接判断\(\dfrac{v}{a+b+c}\)的余数即可
点击查看代码
#include <cstdio>
int main()
{
int v, a, b, c; scanf("%d%d%d%d", &v, &a, &b, &c);
int num = v % (a + b + c);
if (num < a) putchar('F');
else if (num < a + b) putchar('M');
else putchar('T');
return 0;
}
B
对于第一种情况直接判断
第二种情况记录这个数是否出现过再判断就行
点击查看代码
#include <cstdio>
#include <map>
std::map<int, int> flag;
int a[1005], b[1005], sum1, sum2;
int main()
{
int n; scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
flag[a[i]]++;
}
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
if (b[i] == a[i]) sum1++;
if (flag[b[i]] >= 2) sum2++;
else if (flag[b[i]] && a[i] != b[i]) sum2++;
flag[b[i]]++;
}
printf("%d\n%d", sum1, sum2);
return 0;
}
C
首先,只有在同一行的点才可能发生碰撞
对于同一行的点,只要有\(x_i<x_j\)且\(s_i=R,s_j=L\)就会发生碰撞
点击查看代码
#include <cstdio>
#include <algorithm>
struct Node{
int x, y;
char ch;
} a[200005];
char s[200005];
bool cmp(Node &a, Node &b) {
if (a.y != b.y) return a.y < b.y;
return a.x < b.x;
}
int main()
{
for (int i = 1; i <= 200003; i++) {
a[i].x = a[i].y = -1;
a[i].ch = 'a';
}
int n; scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &a[i].x, &a[i].y);
scanf("%s", s);
for (int i = 0; i < n; i++) a[i + 1].ch = s[i];
std::sort(a + 1, a + n + 1, cmp);
for (int i = 1; i < n; i++) {
bool flag = false;
while (a[i].y == a[i + 1].y) {
if (a[i].ch == 'R') flag = true;
if (flag && a[i].ch == 'L') {printf("Yes"); return 0;}
i++;
}
if (a[i].ch == 'R') flag = true;
if (flag && a[i].ch == 'L') {printf("Yes"); return 0;}
}
printf("No");
return 0;
}
D
先访问儿子在访问父亲显然相当于没访问
所以开一个栈记录访问顺序,对于所有属于上述情况的访问全部弹出栈
然后按常规操作模拟即可
点击查看代码
#include <cstdio>
#define ll long long
int top;
char st[1000005] = {'U'}, ch[1000005];
int main()
{
ll n, x; scanf("%lld%lld", &n, &x);
scanf("%s", ch);
for (int i = 0; i < n; i++) {
if (ch[i] == 'U' && st[top] != 'U') top--;
else st[++top] = ch[i];
}
for (int i = 1; i <= top; i++) {
if (st[i] == 'U') x >>= 1;
else x = (x << 1) + (st[i] == 'R');
}
printf("%lld", x);
return 0;
}
E
注意到\(n\leq 300\),所以可以直接\(\operatorname{Floyd}\)求最短路
最后枚举每条边,如果它是最短路上的一条边那就不能删,记录这样的边的数目为\(ans\)
最后答案就是\(m-\dfrac{ans}{2}\)
点击查看代码
#include <cstdio>
#include <algorithm>
const int N = 305;
long long dis[N][N], ans;
int main()
{
int n, m; scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dis[i][j] = 1e18 + 7;
for (int i = 1; i <= n; i++) dis[i][i] = 0;
for (int i = 1; i <= m; i++) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
dis[a][b] = dis[b][a] = c;
}
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dis[i][j] = std::min(dis[i][j], dis[i][k] + dis[k][j]);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int flag = 1;
if (i == j) continue;
for (int k = 1; k <= n; k++)
if (k != i && k != j && dis[i][j] == dis[i][k] + dis[k][j])
flag = 0;
ans += flag;
}
}
printf("%lld", m - ans / 2);
return 0;
}
F
题意
\(\operatorname{Takahashi}\) 在抽奖,他每次会抽取 \(n\) 个奖品中的一个,抽到奖品 \(i\) 的概率为 $\dfrac{W_i}{\sum_{j=1}^nW_j} $ ,问 \(\operatorname{Takahashi}\) 抽 \(k\) 次奖抽到 \(m\) 个不同奖品的概率是几?对 \(998244353\) 取模。
题解
我们考虑在抽奖 \(k\) 次后第 \(i\) 个奖品获得 \(c_i\) 次的概率:显然为 \(\dfrac{k!}{\prod_{i=1}^n(c_i!)}\prod_{i=1}^np_i^{c_i}\) 其中 \(p_i\) 为抽到奖品 \(i\) 的概率
设 \(f_{i,j,k}\)表示前 \(i\) 个奖品抽 \(k\) 次,抽中 \(j\) 个不同奖品的概率
答案就是 \(f_{n,m,k}\times k!\)
点击查看代码
#include <cstdio>
typedef long long ll;
const ll mod = 998244353;
ll f[55][55][55];
ll fac[55], invf[55];
ll w[55], p[55];
ll inv(ll x) {
return x == 1 ? 1 : (mod - mod / x) * inv(mod % x) % mod;
}
ll mul(ll a, ll b) {
ll res = 1;
for (; b != 0; b--) res = res * a % mod;
return res;
}
int main()
{
fac[0] = 1;
for (int i = 1; i <= 50; i++)
fac[i] = fac[i - 1] * i % mod;
invf[50] = inv(fac[50]);
for (int i = 50; i > 0; i--)
invf[i - 1] = invf[i] * i % mod;
int n, m, K;
scanf("%d%d%d", &n, &m, &K);
ll sum = 0;
for (int i = 1; i <= n; i++) {
scanf("%lld", &w[i]);
sum = (sum + w[i]) % mod;
}
ll invs = inv(sum);
for (int i = 1; i <= n; i++)
p[i] = w[i] * invs % mod;
f[0][0][0] = 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j <= m; j++) {
for (int k = 0; k <= K; k++) {
for (int l = 0; l <= K - k; l++) {
int add = (l != 0);
f[i + 1][j + add][k + l] += f[i][j][k] * invf[l] % mod * mul(p[i + 1], l);
f[i + 1][j + add][k + l] %= mod;
}
}
}
}
printf("%lld", f[n][m][K] * fac[K] % mod);
return 0;
}
G
首先有一个十分显然的\(O(\sqrt{x})\)做法
只需要递推+记忆化搜索搞一搞就行
正解:
设 \(A_{n-1}\) 是 \(X\) ,\(A_{n+1}\) 是 \(i\) ,那么 \(A_n\) 就在 \(\lfloor\sqrt X\rfloor\)和\(i^2\)之间
也就是\(f_X=\sum\limits_{i=1}^{\lfloor X^{\frac{1}{4}}\rfloor}(\lfloor\sqrt X\rfloor-i^2+1)f_i\)
点击查看代码
#include <cstdio>
#include <cmath>
typedef long long ll;
ll f[60005], sum[60005];
ll _sqrt(ll x) {
ll x2 = std::sqrt(x) - 1;
while (x2 + 1 <= x / (x2 + 1)) x2++;
return x2;
}
int main()
{
f[1] = sum[1] = 1;
for (int x = 2; x < 60000; x++) {
f[x] = sum[_sqrt(x)];
sum[x] = sum[x - 1] + f[x];
}
int T; scanf("%d", &T);
while (T--) {
ll x; scanf("%lld", &x);
ll x2 = _sqrt(x), x3 = _sqrt(x2);
ll ans = 0;
for (ll i = 1; i <= x3; i++)
ans += (x2 - i * i + 1) * f[i];
printf("%lld\n", ans);
}
return 0;
}

浙公网安备 33010602011771号