題意:你現在有m+1個數:第乙個為p,最小值為0,最大值為n;剩下m個都是無窮,沒有最小值或最大值。
你可以進行任意多輪操作,每輪操作如下:
在不為最大值的數中等概率隨機選擇乙個(如果沒有則不操作),把它加一;
進行k次這個步驟:在不為最小值的數中等概率隨機選擇乙個(如果沒有則不操作),把它減一。
現在問期望進行多少輪操作以後第乙個數會變為最小值0。
這題中的最大值指的是n,最小值指的是0
首先求出f[i]代表經過k次-1操作後,第乙個位置減少了i的概率,那麼f[i]=c(k,i)*(1 / (m+1))^k*(m / (m + 1))^k
記a[i][j]表示第1個數字當前為i,經過第一次操作後變成了j,顯然j不超過i+1
a[i][i+1]=(1 / (m+1)) * (m / (m+1))^k(第一次+1加到了第一位,後面k次-1都沒減到第一位)
a[i][i]=(m / (m + 1)) ^ (k + 1) + (1 / (m + 1)) * f[1] (一種情況是k+1次操作都不在第一位,另一種是1這個位置一開始+1,後面某次操作減1)
a[i][j]=(1 / (m+1)) * f[i - j + 1] + (m / (m + 1)) * f[i - j] (2種情況就是第一次加法有沒有加到第一位上)
記f[i]代表1號位置上數為i,到達終點狀態(1號位置數為0)的期望,顯然f[0]=0;
f[i]=a[i][i+1] * (f[i + 1] + 1) + a[i][i] * (f[i] + 1) + a[i][i - 1] * (f[i - 1] + 1) ..我們可以把加1提到最後面
暴力思路就是直接高消,但是我們可以把每個式子f[i+1]提出來,表示成k*f[1]+b,然後到f[n]就會有2個狀態,解出即可。
但是這題資料真***的坑啊,邊界一堆,菜雞就寫了個高消處理特殊資料,還好這題的特殊資料n都很小
**:
#include#include#include#include#includeusing namespace std;
const int maxn = 1505;
const int mod = 1000000007;
int t;
int n, m, p, k, i, j, k;
int f[maxn], a[maxn][maxn];
int c[maxn], ans[maxn];
inline int add(int x, int y)
struct sb;
} inline sb friend operator * (const sb &a, const int &b)
; }};sb g[maxn];
inline int get()
inline int ksm(int x, int y, int z)
return b;
}int main()
if (!m && k <= 1)
for(i = 1; i <= n; i ++)
for(j = 1; j <= n + 1; j ++)
a[i][j] = 0;
c[0] = 1;
for(i = 0; i < k + 1 && i < n; i ++)
c[i + 1] = (long long)c[i] * (k - i) % mod * ksm(i + 1, mod - 2, mod) % mod;
int invm = ksm(m + 1, mod - 2, mod);
memset(f, 0, sizeof(f));
for(i = 0; i <= k && i <= n; i ++)
f[i] = (long long)c[i] * ksm(invm, i, mod) % mod * ksm(m, k - i, mod) % mod * ksm(invm, k - i, mod) % mod;
int remain = ((long long)ksm(m, k + 1, mod) * ksm(invm, k + 1, mod) +
(long long)f[1] * invm) % mod;
for(i = 1; i < n; i ++)
for(i = n; i >= 0 && i >= n - k; i --)
a[n][i] = f[n - i];
if (m)
; for(i = 1; i < n; i ++)
;for(j = 1; j <= i; j ++)
g[i + 1] = g[i + 1] + g[j] * a[i][j];
// cout << g[i + 1].k << " " << g[i + 1].b << endl;
int r = ksm(mod - a[i][i + 1], mod - 2, mod);
g[i + 1] = g[i + 1] * r;
}sb now = (sb);
for(i = 1; i < n; i ++)
now = now + g[i] * a[n][i];
now = now * ksm(mod + 1 - a[n][n], mod - 2, mod);
if (!g[n].k && !g[n].b) ans[1] = now.b;
else if (now.k == g[n].k) ans[1] = now.b;
else ans[1] = (long long)(now.b - g[n].b + mod) * ksm(g[n].k - now.k + mod, mod - 2, mod) % mod;
printf("%d\n", ((long long)g[p].k * ans[1] + g[p].b) % mod);
continue;
} for(i = 1; i <= n; i ++)
a[i][n + 1] = mod - 1, a[i][i] --;
for(i = 1; i <= n; i ++)
if (k != i)
int inv = ksm(a[i][i], mod - 2, mod);
for(j = 1; j <= n + 1; j ++)
a[i][j] = (long long)a[i][j] * inv % mod;
for(j = 1; j <= n; j ++)
if (j != i && a[j][i])
} printf("%d\n", (a[p][n + 1] + mod) % mod);
}}
bzoj 5294 Bjoi2018 二進位制
pupil 發現對於乙個十進位制數,無論怎麼將其的數字重新排列,均不影響其是不是333 的倍數。他想研究對於二進 制,是否也有類似的性質。於是他生成了乙個長為n 的二進位制串,希望你對於這個二進位制串的乙個子區間,能求出 其有多少位置不同的連續子串,滿足在重新排列後 可包含前導0 是乙個3 的倍數。...
BZOJ 2535 Plane 航空管制2
題意 n個飛機一次出航。第i個飛機在出航序列中的序號不大於ki。另外有一些限制,表示飛機a的出航序號小於飛機b。1 輸出乙個合法的出航序列 2 輸出每個飛機最早的出航序號。思路 參考這裡。第一問比較好搞定。對於給出的,我們不妨建立有向邊。那麼b的所有孩子的出航序號必然小於b的出航序號。按照這個拓撲排...
BZOJ 2199奶牛議會 2 SAT
傳送門 bzoj2199 許可權題?沒關係,你洛上也有 洛谷 usaco11jan 大陸議會the continental cowngress 一道2 sat簡單題。只需要用到2 sat連有向邊的操作,拓撲排序和縮點都不需要,直接暴力找 非常之暴力 include using namespace s...