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号
浙公网安备 33010602011771号