2019年牛客多校第二場

A:Eddy Walker

題意:

給你一個n的點的環,一開始從0號點開始,每次可以前進1或者後退1,問第一次站在m號點的時候已經遍歷完所有點的概率,求出前綴概率積

思路:

一:

暴力打表找規律

#include<bits/stdc++.h>
using namespace std;

double p[10];
bool vis[10];
int n;

bool Check() {
    for (int i = 0; i < n; i ++)
        if(!vis[i]) return false;
    return true; 
}

void dfs(int idx, double px) {
    if(px < 1e-10) return ;
    vis[idx] = 1;
    if(!Check()) {
        int nxt = (idx+1)%n;
        int tmp = vis[nxt];
        vis[nxt] = 1;
        dfs(nxt, px*0.5);
        vis[nxt] = tmp;
        nxt = (idx-1+n)%n;
        tmp = vis[nxt];
        vis[nxt] = 1;
        dfs(nxt, px*0.5);
        vis[nxt] = tmp;
    }else p[idx] += px;
}


int main() {
    for (n = 1; n <= 7; n ++) {
        printf("n: %d\n", n);
        memset(p, 0, sizeof(p));
        memset(vis, 0, sizeof(vis));
        dfs(0, 1);
        for (int i = 0; i < n; i ++) {
            printf("i: %d, p: %lf\n", i, p[i]);
        }
    }
    return 0;
}

在這裏插入圖片描述

這是打表的結果,可以發現結果與m無關(當m>0時)而且近似爲1n1\frac{1}{n-1}

二:
數學分析:
因爲是最後站在一個非0的位置上,而每個非零的點的最後一次到達的概率是相同的,所以是1n1\frac{1}{n-1}

B:Eddy Walker2

題意:

現在是給你一條鏈,從0點出發,一個最多走k步,每一步的概率都是1k\frac{1}{k} ,問最後走到n的概率

思路:

根據題意可以寫出一個遞推式子:

dp[i]=1ki=1kdp[ni]dp[i] = \frac{1}{k}\sum\limits_{i=1}^{k}dp[n-i]

如果n很小的話,可以直接用dp來寫,但是n的大小是1e91e^{9},所以我們就得用BM直接套板子線性遞推

但是有一個問題,就是n可能爲無窮,我們可以這樣來寫,

我們每次行動的移動記錄期望是1ki=1ki=(k+1)k2k=k+12\frac{1}{k}\sum\limits_{i=1}^{k}i=\frac{(k+1)k}{2k}=\frac{k+1}{2} ,也就是每行動一次大概移動k+12\frac{k+1}{2} ,而我們移動到n的次數可能爲m次,那麼移動的距離期望就是(k+1)m2\frac{(k+1)m}{2} 而n在其中,在這(k+1)m2\frac{(k+1)m}{2}個點中,我們一共會走m個點,那麼就是n在這m個點之間的概率1m\frac{1}{m} , 期望就是mm ,而在整體的概率就是m(k+1)m2=2k+1\frac{m}{\frac{(k+1)m}{2}}=\frac{2}{k+1}

dp[i]={1k(dp[i1]+dp[i2]+...+dp[ik]),i&gt;=k2k+1,i=dp[i]=\begin{cases} \frac{1}{k}\cdot (dp[i-1]+dp[i-2]+...+dp[i-k]),i&gt;=k\\ \frac{2}{k+1},i=\infty \\\end{cases}

AC代碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9 + 7;
#define sz(x) ((int)(x).size())
typedef vector<ll> VI;
 
ll Ksm(ll a, ll b) {
    ll res = 1; a %= mod;
    assert(b >= 0);
    while(b) {
        if(b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
 
int _, n;
namespace Linear_Seq{
    const int N = 10010;
    ll res[N], base[N], _c[N], _md[N];
    vector<int> Md;
     
    void Mul(ll *a, ll *b, int k) {
        for (int i = 0; i < k+k; i ++) _c[i] = 0;
        for (int i = 0; i < k; i ++)
            if(a[i]) for (int j = 0; j < k; j ++)
                _c[i+j] = (_c[i+j] + a[i]*b[j]) % mod;
        for (int i = k + k - 1; i >= k; i --)
            if(_c[i]) for (int j = 0; j < sz(Md); j ++)
                _c[i-k+Md[j]] = (_c[i-k+Md[j]] - _c[i] * _md[Md[j]]) % mod;
        for (int i = 0; i < k; i ++)
            a[i] = _c[i];
    }
 
    int solve(ll n, VI a, VI b) {
        ll ans = 0, pnt = 0;
        int k = sz(a);
        assert(sz(a) == sz(b));
        for (int i = 0; i < k; i ++) _md[k-1-i] = -a[i];
        _md[k] = 1; Md.clear();
        for (int i = 0; i < k; i ++) 
            if(_md[i]) Md.push_back(i);
        for (int i = 0; i < k; i ++) res[i] = base[i] = 0;
        res[0] = 1;
        while((1ll<<pnt) <= n) pnt ++;
        for (int p = pnt; p >= 0; p --) {
            Mul(res, res, k);
            if((n>>p) & 1) {
                for (int i = k-1; i >= 0; i --) res[i+1] = res[i];
                res[0] = 0;
                for (int j = 0; j < sz(Md); j ++)
                    res[Md[j]] = (res[Md[j]] - res[k] * _md[Md[j]]) % mod;
            }
        }
        for (int i = 0; i < k; i ++) ans = (ans + res[i] * b[i]) % mod;
        if(ans < 0) ans += mod;
        return ans;
    }
 
    VI BM(VI s) {
        VI C(1, 1), B(1, 1);
        int L = 0, m = 1, b = 1;
        for (int n = 0; n < sz(s); n ++) {
            ll d = 0;
            for (int i = 0; i < L + 1; i ++) d = (d + (ll)C[i] * s[n-i]) % mod;
            if (d == 0) ++m;
            else if(2 * L <= n) {
                VI T = C;
                ll c = mod - d * Ksm(b, mod-2) % mod;
                while(sz(C) < sz(B) + m) C.push_back(0);
                for (int i = 0; i < sz(B); i ++) C[i+m] = (C[i+m] + c * B[i]) % mod;
                L = n + 1 - L; B = T;
                b = d; m = 1;
            }else {
                ll c = mod - d * Ksm(b, mod-2) % mod;
                while(sz(C) < sz(B) + m) C.push_back(0);
                for (int i = 0; i < sz(B); i ++) C[i+m] = (C[i+m] + c * B[i]) % mod;
                ++ m;
            }
        }
        return C;
    }
 
    int Gao(VI a, ll n) {
        VI c = BM(a);
        c.erase(c.begin());
        for (int i = 0; i < sz(c); i ++) c[i] = (mod-c[i]) % mod;
        return solve(n, c, VI(a.begin(), a.begin()+sz(c)));
    }
};
using namespace Linear_Seq;
 
void solve() {
    ll n, k;
    scanf("%lld %lld", &k, &n);
    if(n == 0) {
        printf("1\n");
        return ;
    }else if(n == -1) {
        printf("%lld\n", 2 * Ksm(k+1, mod-2) % mod);
        return ;
    }
    VI dp(3*k, 0), v;
    dp[0] = 1;
    v.push_back(1);
    for (int i = 1; i <= k; i ++) {
        for (int j = 0; j < i; j ++)
            dp[i] = (dp[i] + dp[j]) % mod;
        dp[i] = dp[i] * Ksm(k, mod-2) % mod;
        v.push_back(dp[i]);
    }
    for (int i = k+1; i <= 2 * k; i ++) {
        for (int j = 1; j <= k; j ++)
            dp[i] = (dp[i] + dp[i-j]) % mod;
        dp[i] = dp[i] * Ksm(k, mod-2) % mod;
        v.push_back(dp[i]);
    }
    printf("%lld\n", Gao(v, n));
}
 
int main() {
    int T;
    scanf("%d", &T);
    while(T --)
        solve();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章