bzoj5292 bjoi2018 治療之雨

2021-08-19 16:37:54 字數 3245 閱讀 8502

題意:你現在有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...