题解(期望dp)2023.6.7

期望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;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值