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