[CF850F]Rainbow Balls / [DarkBZOJ2554]Color

280 篇文章 1 订阅

题目

传送门 to luogu

传送门 to DarkBZOJ

思路

第一步转化:分类讨论。每个颜色提供的贡献是独立可加的。

枚举某种颜色最后胜利,则其余颜色可视为相同。于是只需要求出该颜色的数量为 k k k 时的信息。

首先令 f ( x ) f(x) f(x) 表示结束的概率。注意到该颜色减少和增加的概率是相同的,都是 x ( n − x ) n ( n − 1 ) x(n-x)\over n(n-1) n(n1)x(nx),因此必定有方程式

显然,这就是数量增加 1 1 1 (与减少 1 1 1 )的概率,写出递推方程式
f ( x ) = f ( x − 1 ) + f ( x + 1 ) 2 f(x)=\frac{f(x{-}1)+f(x{+}1)}{2} f(x)=2f(x1)+f(x+1)

这个式子是等差数列的另一种表示方法,结合边界条件 f ( 0 ) = 0 ,    f ( n ) = 1 f(0)=0,\;f(n)=1 f(0)=0,f(n)=1 可知
f ( x ) = x n f(x)=\frac{x}{n} f(x)=nx

然后令 g ( x ) g(x) g(x) 表示期望。令 p x = x ( n − x ) n ( n − 1 ) p_x={x(n-x)\over n(n-1)} px=n(n1)x(nx),则
g ( x ) = ( 1 − 2 p x ) g ( x ) + p x [ g ( x − 1 ) + g ( x + 1 ) ] + f ( x ) g(x)=(1-2p_x)g(x)+p_x[g(x{-}1)+g(x{+}1)]+f(x) g(x)=(12px)g(x)+px[g(x1)+g(x+1)]+f(x)

这与上面的式子是等价的。注意是 + f ( x ) +f(x) +f(x),尽管这是常识,但容易忘。

方程可以变形为
2 g ( x ) − g ( x − 1 ) − g ( x + 1 ) = f ( x ) p x (1) 2g(x)-g(x{-}1)-g(x{+}1)=\frac{f(x)}{p_x}\tag{1} 2g(x)g(x1)g(x+1)=pxf(x)(1)

边界是 g ( 0 ) = g ( n ) = 0 g(0)=g(n)=0 g(0)=g(n)=0 。这玩意儿转移有环;怎么解方程?

生成函数

H ( x ) = ∑ k ⩾ 1 f ( k ) p k x k + 1 H(x)=\sum_{k\geqslant 1}\frac{f(k)}{p_k}x^{k+1} H(x)=k1pkf(k)xk+1,显然答案的生成函数为
G ( x ) = − H ( x ) + x g ( 1 ) ( 1 − x ) 2 G(x)=\frac{-H(x)+xg(1)}{(1-x)^2} G(x)=(1x)2H(x)+xg(1)

我们只需解 g ( 1 ) g(1) g(1) 使得 [ x n ] G ( x ) = 0 [x^n]G(x)=0 [xn]G(x)=0

H ( x ) H(x) H(x) 没有闭形式,我们就不要再考虑 G F \rm GF GF 了,回到普通计算数学上面来。
[ x n ] G ( x ) = n g ( 1 ) − ∑ i = k n − 1 f ( k ) p k ( n − k ) = n g ( 1 ) − ( n − 1 ) 2 [x^n]G(x)=ng(1)-\sum_{i=k}^{n-1}\frac{f(k)}{p_k}(n{-}k)=ng(1)-(n{-}1)^2 [xn]G(x)=ng(1)i=kn1pkf(k)(nk)=ng(1)(n1)2

于是解出了 g ( 1 ) = ( n − 1 ) 2 n g(1)={(n-1)^2\over n} g(1)=n(n1)2,就知足吧。

花絮:我非要拼凑 H ( x ) H(x) H(x) 闭形式,因此将 G ( x ) G(x) G(x) 翻转并递推,就会解出 g ( n − 1 ) = n ( H n − 1 ) g(n{-}1)=n(H_{n}{-}1) g(n1)=n(Hn1),其中 H n = ∑ j = 1 n 1 j H_n=\sum_{j=1}^{n}\frac{1}{j} Hn=j=1nj1 是调和级数,没有快速求解的方法。

初等方法

( 1 ) (1) (1) 式为关于 x x x 的方程。

1 ⩽ l ⩽ r ⩽ n 1\leqslant l\leqslant r\leqslant n 1lrn 。对所有 k ∈ [ l , r ] k\in[l,r] k[l,r],将 k k k 的方程求和(等式左右分别相加),则有
g ( l ) + g ( r ) − g ( l − 1 ) − g ( r + 1 ) = ∑ k = l r f ( k ) p k g(l)+g(r)-g(l{-}1)-g(r{+}1)=\sum_{k=l}^{r}\frac{f(k)}{p_k} g(l)+g(r)g(l1)g(r+1)=k=lrpkf(k)

l = 1 l=1 l=1 就得到
g ( 1 ) + g ( r ) = g ( 0 ) + g ( r + 1 ) + ∑ k = 1 r f ( k ) p k g(1)+g(r)=g(0)+g(r{+}1)+\sum_{k=1}^{r}\frac{f(k)}{p_k} g(1)+g(r)=g(0)+g(r+1)+k=1rpkf(k)

联立 g ( 0 ) = 0 g(0)=0 g(0)=0 就有

g ( x ) = g ( x + 1 ) − g ( 1 ) + ∑ i = 1 k f ( k ) p k g(x)=g(x{+}1)-g(1)+\sum_{i=1}^{k}\frac{f(k)}{p_k} g(x)=g(x+1)g(1)+i=1kpkf(k)

注意到它描述的其实是 Δ g \Delta g Δg 。那么求和容易得到
g ( x ) = g ( n ) − ( n − x ) g ( 1 ) + ∑ i = x n − 1 ∑ j = 1 i f ( j ) p j g(x)=g(n)-(n{-}x)g(1)+\sum_{i=x}^{n-1}\sum_{j=1}^{i}\frac{f(j)}{p_j} g(x)=g(n)(nx)g(1)+i=xn1j=1ipjf(j)

x = 1 x=1 x=1 后化简式子可知 g ( 1 ) = ( n − 1 ) 2 n g(1)={(n-1)^2\over n} g(1)=n(n1)2

代码

这里放出 CF850F Rainbow Balls 的代码。复杂度可以做到线性,但没必要。

#include <cstdio>
#include <algorithm> // Almighty XJX yyds!!
#include <cstring> // oracle: ZXY yydBUS!!!
#include <cctype> // rainybunny root of the evil.
using llong = long long;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
# define rep0(i,a,b) for(int i=(a); i!=(b); ++i)
inline int readint(){
    int a = 0, c = getchar(), f = 1;
    for(; !isdigit(c); c=getchar()) if(c == '-') f = -f;
    for(; isdigit(c); c=getchar()) a = a*10+(c^48);
    return a*f;
}

const int MAXA = 100000, MOD = 1e9+7;
inline llong qkpow(llong b, int q){
    llong a = 1;
    for(; q; q>>=1,b=b*b%MOD) if(q&1) a = a*b%MOD;
    return a;
}

const int MAXN = 2500;
int a[MAXN+1], inv[MAXA+1];

int g[MAXA+1];
int main(){
    int n = readint(), s = 0;
    rep(i,1,n) s += (a[i] = readint());
    rep(i,0,MAXA) inv[i] = int(qkpow(s-i,MOD-2));
    g[0] = 0, g[1] = int(llong(s-1)*(s-1)%MOD*inv[0]%MOD);
    rep0(i,1,MAXA){
        g[i+1] = int((llong(g[i]<<1)-g[i-1]
            -llong(s-1)*inv[i])%MOD);
        if(g[i+1] < 0) g[i+1] += MOD;
    }
    int ans = 0;
    rep(i,1,n) ans = (ans+g[a[i]])%MOD;
    printf("%d\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值