省选测试18

A 飞行棋

题目大意 : 走棋,问每个人获胜的概率是多少

  • 定义dp[i][j]表示走i次能从j到n的概率,dp[i]从dp[i-1]转移而来

Code

Show Code
#include <cstdio>
#include <cstring>

using namespace std;
const int N = 160;
const double eps = 1e-8;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
    return x * f;
}

int n, m, t[N], a[N];
double f[2][N], s, q[N], p[N];

int main() {
    n = read(); m = read();
    if (m == 1) return puts("1"), 0;
    for (int i = 1; i <= n; ++i) 
        t[i] = read();
    for (int i = 1; i <= m; ++i) 
        a[i] = read(), q[i] = 1;// q[i] 表是当前第i个人不能到达n的概率
    for (int i = 1; i < 6; ++i)
        t[n+i] = t[n];
    s = f[0][n] = 1;//s 表示当前没有一个人能到达n的概率
    for (int i = 1; s > eps; i ^= 1) {
        memset(f[i], 0, sizeof(f[i]));
        for (int j = 1; j < n; ++j) {
            for (int k = 1; k <= 6; ++k)
                f[i][j] += f[i^1][t[j+k]];
            f[i][j] /= 6;
        }
        for (int j = 1; j <= m; ++j) {
            s /= q[j];
            p[j] += f[i][a[j]] * s;
            q[j] -= f[i][a[j]];
            s *= q[j];
        }
    }
    for (int i = 1; i <= m; ++i)
        printf("%.9lf
", p[i]);
    return 0;
}

B 字符串难题

题目大意 : 给n个01串,有的地方是?,问在所有情况下建出trie树后节点个数的和

  • trie树节点个数其实就是不同的前缀个数(含空串),而n只有20,可以子集反演

  • 定义f[i]表示在集合里的串的最长公共前缀比i大的情况数,转移的话就是如果这一位全是?,那么f[i]=2f[i-1],如果有0也有1,说明最长公共前缀不可能有这么长,f[i]=0,否则的话可以将?改为0或1,所以f[i]=f[i-1]

Code

Show Code
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 55, M = 998244353;

char c[N][N];
int n, len[N], tot, f[N*N], a[N], p[N*N], ans;

int main() {
    scanf("%d", &n); 
    for (int i = 1; i <= n; ++i) {
        scanf("%s", c[i] + 1);
        len[i] = strlen(c[i] + 1);
        for (int j = 1; j <= len[i]; ++j)
            if (c[i][j] == '?') tot++;
    }
    p[0] = f[0] = 1;
    for (int i = 1; i <= tot; ++i)
        p[i] = p[i-1] * 2 % M;
    for (int s = (1 << n) - 1; s >= 1; --s) {
        int sum = 0, cnt = 0, mi = 1e9;
        for (int i = 1; i <= n; ++i)
            if (s >> i - 1 & 1) 
                a[++cnt] = i, mi = min(mi, len[i]);
        for (int j = 1; j <= mi; ++j) {
            int s0 = 0, s1 = 0, s2 = 0;
            for (int i = 1; i <= cnt; ++i) {
                if (c[a[i]][j] == '0') s0++;
                else if (c[a[i]][j] == '1') s1++;
                else s2++, sum++;
            }
            if (s2 == cnt) f[j] = f[j-1] * 2 % M;
            else if (!s0 || !s1) f[j] = f[j-1];
            else f[j] = 0;
            ans = (ans + 1ll * p[tot-sum] * f[j] * (cnt & 1 ? 1 : -1) % M + M) % M;
        }
    }
    printf("%d
", (ans + p[tot]) % M);
    return 0;
}```

</details>

<br>

# C 障碍雷达 (Unaccepted)

题目大意 : 

* 咕咕

## Code

<details><summary>Show Code</summary>

```cpp
原文地址:https://www.cnblogs.com/shawk/p/14386432.html