题解:P15985 [PA 2026] 骰子 / Kostki
zhang_kevin · · 题解
考察『当前得分最低的人得分恰为
-
某人得分直接飙升到
\geq m :游戏结束。 -
所有
x 人均完成操作且分数< m :最小值将永远> i 。
在这一连串行动中,每次操作前的分数均为
那么在最小值为
-
若
p = 0 ,则无法结束,显然C(x) = x 。 -
若
p > 0 ,则相当于进行一个最多x 次的伯努利试验序列,期望次数为:
接下来考察『单个玩家的独立操作过程』。显然这个人在操作过程中关于一个分数
-
得分恰好为
i :设其概率为f_i 。 -
得分从
< i 变成(i, m) 之间:设其概率为g_i 。 -
得分从
< i 变到[m, +\infty) :显然这个人得分首次\geq i 时游戏已经结束,概率为1 - f_i - g_i 。
在真实游戏过程中,如果所有人都
将上面所说的相结合,即得分数最小值为
带入
-
当
p = 0 时:C(x) = x ,故E_i = \sum\limits_{x = 0}^n \binom{n}{x} x f_i^x g_i^{n - x} = nf_i(f_i + g_i)^{n - 1} 。 -
当
p > 0 时,带入C(x) = \frac{1 - (1 - p)^x}{p} ,于是:
最后总行动次数的期望
最后考虑如何计算
对于
前缀和或滑动窗口优化即可做到
对于一个分数
稍微推一下,可以得到:
用你喜欢的方法优化一下也可以做到
由于需要快速幂,因此总时间复杂度为
参考代码:
namespace Solution{
const int mo = 1e9 + 7;
int n, k, m, f[1000005], sf[1000005], g[1000005], da[1000005], db[1000005];
inline int mod(ll x){return (x % mo + mo) % mo;}
inline int fp(int a, int b){
int res = 1;
while(b){
if(b & 1) res = (ll)res * a % mo;
a = (ll)a * a % mo;
b >>= 1;
}
return res;
}
inline int inv(int x){return fp(x, mo - 2);}
inline int sumf(int l, int r){return mod((ll)sf[r] - sf[l] + f[l]);}
inline int P(int i){
if(m - i <= k) return (ll)(k - m + i + 1) * inv(k) % mo;
return 0;
}
inline void Solve(){
rd(n, k, m); const int invk = inv(k);
f[0] = 1; fu(i, 1, m){
f[i] = (ll)invk * sumf(max(0, i - k), i - 1) % mo;
sf[i] = (sf[i - 1] + f[i]) % mo;
}
fu(x, 0, m - 1){
int l = x + 1, r = (m - 1 - x >= k) ? (x + k) : (m - 1), c = r;
if(l <= r){
int a = (ll)f[x] * c % mo, b = mo - f[x];
da[l] = (da[l] + a) % mo, da[r + 1] = (da[r + 1] - a + mo) % mo;
db[l] = (db[l] + b) % mo, db[r + 1] = (db[r + 1] - b + mo) % mo;
}
}
int suma = 0, sumb = 0;
fu(i, 0, m){
suma = (suma + da[i]) % mo, sumb = (sumb + db[i]) % mo;
g[i] = (ll)((ll)sumb * i % mo + suma) % mo * invk % mo;
}
// fu(i, 0, m) cerr << f[i] << ' ' << g[i] << '\n';
int ans = 0;
fu(i, 0, m){
int p = P(i), Ei = 0;
if(p == 0){
Ei = (ll)n * f[i] % mo * fp((f[i] + g[i]) % mo, n - 1) % mo;
}else{
int t1 = fp((f[i] + g[i]) % mo, n);
int t2 = fp(mod((ll)mod(1 - p) * f[i] % mo + g[i]), n);
Ei = (ll)inv(p) * mod(t1 - t2) % mo;
}
ans = (ans + Ei) % mo;
}
wr(ans), pc('\n');
return;
}
}