Good Bye 2017 D. New Year and Arbitrary Arrangement[dp II][概率论][数论]
题目:http://codeforces.com/contest/908/problem/D
题意:每次有$\frac{pa}{pa+pb}$的概率选择‘a’,有$\frac{pb}{pa+pb}$的概率选择‘b’,每当串中出现k个ab(不一定连续)时停止操作,输出期望。
分析:乱七八糟的东西用逆元处理一下,dp中必然包含出现的ab个数,但是无法转移,所以再存一维作为a的个数。
dp[i][j]代表前面有i个a,有j个ab的情况数。转移的状态非常好想,下一个是a就转移到dp[i+1][j],如果是b就转移到dp[i][i+j],因为前缀的b并不会产生任何贡献,所以令dp[1][0]=1作为初状态(因为第一个如果是b相当于没有,所以抽到a的概率为100%)。
另一个问题就是截止点,题目要求超过k个ab就截止,那么当i+j>=k时抽到b截止,期望为i+j。但是还有情况就是一直抽到a,一直无法结束,这时候算他的基础期望为i+j,有pa的概率抽到a继续,则在下一个状态抽到b时贡献加1。意思就是说,有pa的概率加1,$pa^{2}$的概率加1,一直延伸到无限,用一个等比数列求和公式求n为无穷大时的值,算出后续的贡献为$\frac{pa}{1-pa}$。
所以当i+j>=k时对答案的贡献为$dp[i][j]*(i+j+\frac{pa}{1-pa})$。
代码:
1 #define _CRT_SECURE_NO_DEPRECATE 2 #pragma comment(linker, "/STACK:102400000,102400000") 3 #pragma GCC optimize("Ofast") 4 #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") 5 #include<iostream> 6 #include<cstdio> 7 #include<fstream> 8 #include<iomanip> 9 #include<algorithm> 10 #include<cmath> 11 #include<deque> 12 #include<vector> 13 #include<bitset> 14 #include<queue> 15 #include<string> 16 #include<cstring> 17 #include<map> 18 #include<stack> 19 #include<set> 20 #include<functional> 21 #define pii pair<ll,ll> 22 #define mod 1000000007 23 #define mp make_pair 24 #define pi acos(-1) 25 #define eps 0.00000001 26 #define mst(a,i) memset(a,i,sizeof(a)) 27 #define all(n) n.begin(),n.end() 28 #define lson(x) ((x<<1)) 29 #define rson(x) ((x<<1)|1) 30 #define inf 0x3f3f3f3f 31 typedef long long ll; 32 typedef unsigned long long ull; 33 using namespace std; 34 35 ll extendGcd(ll a, ll b, ll &x, ll &y) { 36 ll ans, t; 37 if (b == 0) { 38 x = 1; y = 0; 39 return a; 40 } 41 ans = extendGcd(b, a%b, x, y); 42 t = x; x = y; y = t - (a / b)*y; 43 return ans; 44 } 45 46 ll getInv(ll a, ll m = mod) { 47 ll x, y, d; 48 d = extendGcd(a, m, x, y); 49 if (d == 1) 50 return (x%m + m) % m; 51 else 52 return -1; 53 } 54 const int maxn = 1e3 + 5; 55 ll dp[maxn][maxn]; 56 int n; 57 58 int main() 59 { 60 ios::sync_with_stdio(false); 61 cin.tie(0); cout.tie(0); 62 int i, j, k, m; 63 int pa, pb; 64 cin >> n >> pa >> pb; 65 ll ans = 0; 66 ll sm = getInv(pa + pb); 67 pa = (pa*sm) % mod; 68 pb = (pb*sm) % mod; 69 dp[1][0] = 1; 70 ll qu = (1 - pa + mod) % mod; 71 qu = (getInv(qu)*pa) % mod; 72 for (ll i = 1; i <= n; ++i) 73 for (ll j = 0; j <= n; ++j) 74 if (i + j >= n) 75 ans = (ans + dp[i][j] * (i + j + qu)) % mod; 76 else 77 { 78 dp[i + 1][j] = (dp[i + 1][j] + dp[i][j] * pa) % mod; 79 dp[i][i + j] = (dp[i][i + j] + dp[i][j] * pb) % mod; 80 } 81 cout << ans << endl; 82 return 0; 83 }