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時)而且近似爲
二:
數學分析:
因爲是最後站在一個非0的位置上,而每個非零的點的最後一次到達的概率是相同的,所以是
B:Eddy Walker2
題意:
現在是給你一條鏈,從0點出發,一個最多走k步,每一步的概率都是 ,問最後走到n的概率
思路:
根據題意可以寫出一個遞推式子:
如果n很小的話,可以直接用dp來寫,但是n的大小是,所以我們就得用BM直接套板子線性遞推
但是有一個問題,就是n可能爲無窮,我們可以這樣來寫,
我們每次行動的移動記錄期望是 ,也就是每行動一次大概移動 ,而我們移動到n的次數可能爲m次,那麼移動的距離期望就是 而n在其中,在這個點中,我們一共會走m個點,那麼就是n在這m個點之間的概率 , 期望就是 ,而在整體的概率就是
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;
}