期望dp
FAVDICE - Favorite Dice
题意:一个n面的骰子,求期望,掷几次能使得每一面都被掷到。
公式推导过程:dp[i]表示已经抛了i种不同面骰子,原来一致概率i/n,不一致n-i/n,
得到转移方程dp[i]=(i/n)dp[i]+((n-i)/n)dp[i+1]+1
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(fast)
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<math.h>
#include<map>
#include<vector>
#include<stack>
#define ms(x,y) memset(x,y,sizeof x);
#define YES cout<<"YES"<<'\n';
#define NO cout<<"NO"<<'\n';
#define endl cout<<'\n';
typedef long long ll;
const int maxn=2e5+10,inf = 1e18 ;
const int mod = 1e9 + 7;
using namespace std;
int a[maxn];
double dp[maxn];
void solve(){
int n;
cin >> n;
dp[n] = 0;
for (int i = n - 1; i >= 0; i--) {
dp[i] = dp[i + 1] + (double)n /(double)(n - i);
}
printf("%.2f\n", dp[0]);
}
signed main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
solve();
}
}
洛谷P4316 绿豆蛙的归宿
思路:dp[i]表示从n到i的的期望长度,x到y的概率为1/入度,贡献值为w,得到公式dp[y]+=(dp[x]+w)/入度
逆推采用拓扑排序和反向建图
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(fast)
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<cstring>
#include<math.h>
#include<map>
#include<vector>
#include<stack>
#define ms(x,y) memset(x,y,sizeof x);
#define YES cout<<"YES"<<'\n';
#define NO cout<<"NO"<<'\n';
#define endl cout<<'\n';
#define int long long
typedef long long ll;
const int maxn=2e5+10,inf = 1e18 ;
const int mod = 1e9 + 7;
using namespace std;
int a[maxn];
int n, m;
struct edge {
int v,w,next;
}e[maxn];
int cnt = 0; int head[maxn];
int in[maxn], degree[maxn];
double dp[maxn];
void insert(int u,int v,int w) {
cnt++;
e[cnt].v = v;
e[cnt].next = head[u];
e[cnt].w = w;
head[u] = cnt;
}
void tuopu() { //拓扑排序
queue<int>q;
for (int i = 1; i <= n; i++) {
if (!in[i]) {
q.push(i);
}
}
while (!q.empty()) {
int now = q.front();
q.pop();
for (int i = head[now]; i; i = e[i].next) {
int v = e[i].v;
dp[v] += (double)(dp[now] + e[i].w)/(double)degree[v]; //转移状态
in[v]--;
if(!in[v]){
q.push(v);
}
}
}
}
void solve(){
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int u, v,w;
cin >> u >> v >> w;
insert(v, u, w); //反向建边,逆推
in[u]++;
degree[u]++; //概率使用
}
tuopu();
printf("%.2f\n", dp[1]);
}
signed main()
{
ios::sync_with_stdio(false);
solve();
}
A 捞钱杯车队
1到n的因数和的和
贡献值(n/i)范围是l,r,每一个l=上一个r+1,r=n/(n/l),等差数列求和乘贡献值,含除法取模采用逆元
#include<iostream>
#define ll long long
using namespace std;
const int mod = 1e9 + 7;
ll q_pow(ll n, ll m){ //费马小定理逆元
int res = 1;
while (m){
if (m & 1){
res = (res * n) % mod;
}
n = (n * n) % mod;
m = m >> 1;
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
ll n, ans = 0;
cin >> n;
ll mod2 = q_pow(2, mod - 2);
for (ll l = 1, r; l <= n; l = r + 1){
r = n / (n / l);
ans = (ans + (((r - l + 1) % mod * ((r + l) % mod)) % mod * mod2 % mod * ((n / l) % mod)) % mod) % mod;
}
cout << ans;
return 0;
}