最简单 概率dp
https://www.luogu.com.cn/problem/P4550
首先我们可以推出已经拿了i个不同牌的期望拿取次数
那么考虑拿了i个不同牌的期望花费,期望花费就可以看作增加的期望拿取次数是\(1\)变成了花费 \(k\) 就是\(f[i] + 1 和 f[i + 1] + 1\),因为题目说第\(k\) 局的花费是\(k\)
double f[maxn], g[maxn];
void run() {
int n; scanf("%d", &n);
for(int i = n - 1; i >= 0; -- i) {
f[i] = f[i + 1] + 1.0 * n / (n - i);
g[i] = 1.0 * i / (n - i) * f[i] + 1.0 * n / (n - i) + g[i + 1] + f[i + 1];
}
printf("%.2lf\n", g[0]);
return ;
}
https://codeforces.com/gym/102861/problem/A
每次花费1可以得到 \([a, b]\) 范围的卡牌,问你拿到 \(n\) 张的期望花费
考虑倒推,\(f[n] = 0, f[i] = \frac {\sum_{j = a}^b f[i + j] + 1} {b - a + 1}\)
特判一下\(a = 0\) 的情况,要移一下项。
double f[maxn];
void run() {
int n, a, b;
scanf("%d %d %d", &n, &a, &b);
double s = 0; int l = (a == 0 ? 1 : a);
for(int i = n - 1; i >= 0; -- i) {
if(a) f[i] = s / (b - a + 1) + 1;
else f[i] = (s + b + 1) / b;
if(i + l - 1 < n) s += f[i + l - 1];
if(i + b < n) s -= f[i + b];
}
printf("%.10lf\n", f[0]);
return ;
}
https://www.luogu.com.cn/problem/P4316
就是每个点的期望都是下一个点的期望推过来的\(f[i] = \sum \frac {f[to[i]]} {sz[i]}\)
因为是无环图,所以考虑拓扑排序递推贡献就行了
int head[maxn], to[maxn], nxt[maxn], val[maxn], ecnt;
void add(int u, int v, int w) {
to[++ecnt] = v; nxt[ecnt] = head[u]; head[u] = ecnt; val[ecnt] = w;
}
double f[maxn];
int sz[maxn], in[maxn];
void run() {
int n, m; scanf("%d %d", &n, &m);
for(int i = 1; i <= m; ++ i) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
add(v, u, w); in[u] ++; sz[u] ++;
}
queue<int> q;
q.push(n);
while(!q.empty()) {
int top = q.front();
q.pop();
for(int i = head[top]; i; i = nxt[i]) {
f[to[i]] += (f[top] + val[i]) / sz[to[i]];
in[to[i]] --;
if(in[to[i]] == 0) q.push(to[i]);
}
}
printf("%.2lf\n", f[1]);
return ;
}
https://vjudge.net/problem/CodeForces-518D
//当t小于等于n,就是t*p
//当t大于n,那么就会有的情况拿满了,不能继续贡献了
//考虑二维递推式,f[i][j]->第i秒有j个人,f[0][0] = 1,表示0的时候期望是1
//f[i][j] = f[i - 1][j - 1] * p + f[i - 1][j] * (j == n ? 1 : (1 - p)),n个人了就不变了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e3 + 10;
constexpr int MOD = 998244353;
double f[maxn][maxn];
void run() {
int n, t; double p;
scanf("%d %lf %d", &n, &p, &t);
f[0][0] = 1;
for(int i = 1; i <= t; ++ i) {
f[i][0] = f[i - 1][0] * (1 - p);
for(int j = 1; j <= n && j <= i; ++ j)
f[i][j] = f[i - 1][j - 1] * p + f[i - 1][j] * (j == n ? 1 : (1 - p));
}
double ans = 0;
for(int i = 1; i <= n && i <= t; ++ i) ans += f[t][i] * i;
printf("%.10lf\n", ans);
return ;
}
signed main() {
int t = 1;
while(t--)
run();
return 0;
}
https://www.luogu.com.cn/problem/P6154
其实就是求所有边的边长和,除以边数+点数
int head[maxn], to[maxn * 10], nxt[maxn * 10], ecnt;
void add(int u, int v) {
to[++ecnt] = v; nxt[ecnt] = head[u]; head[u] = ecnt;
}
int ksm(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return res;
}
int inv(int x) {
if(x >= mod) x -= mod;
return ksm(x, mod - 2);
}
int sz[maxn], in[maxn], num[maxn], val[maxn], sum[maxn];
inline int qmod(int x) {
if(x >= mod) x -= mod;
return x;
}
void run() {
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; ++ i) {
int u, v; scanf("%d %d", &u, &v);
add(v, u); in[u] ++;
}
queue<int> q;
for(int i = 1; i <= n; ++ i) if(in[i] == 0) q.push(i);
for(int i = 1; i <= n; ++ i) sz[i] = 1;
int ans1 = 0, ans2 = 0;
while(!q.empty()) {
int top = q.front();
q.pop();
ans1 += sum[top];
if(ans1 >= mod) ans1 -= mod;
ans2 += sz[top];
cout << top << " " << sz[top] << " " << endl;
if(ans2 >= mod) ans2 -= mod;
for(int i = head[top]; i; i = nxt[i]) {
sz[to[i]] += sz[top];//树的点数
if(sz[to[i]] >= mod) sz[to[i]] -= mod;
sum[to[i]] += qmod(sum[top] + sz[top] * 1/*val[i]*/);//树的连根路径和
if(sum[to[i]] >= mod) sum[to[i]] -= mod;
in[to[i]] --;
if(in[to[i]] == 0) q.push(to[i]);
}
/*for(int i = head[top]; i; i = nxt[i]) {
sz[to[i]] += sz[top];//树的所有点数
val[to[i]] += val[top] + sz[top];//树的所有边数
//num[to[i]] += num[top] + sz[top] * /val[i]/;//直接连边总长
sum[to[i]] += sum[top] + num[top] + sz[top] * /val[i]/;//树的所有路径和
in[to[i]] --;
if(in[to[i]] == 0) q.push(to[i]);
}*/
}
//a * inv(b) = a % mod * inv(b % mod)
printf("%d\n", 1ll * ans1 * inv(ans2) % mod);
return ;
}

浙公网安备 33010602011771号