合并石子 (不是你想象的那个合并石子

合并石子 (初探二项式反演)

排序不亏, 将 ab 从小到大排序.

枚举第 k 大值 x, 将方案数乘上 x 求和, 最后乘上 n! 的逆元.

对于每个 xfi,j 表示后 ia, 选择了 j 个和 b 配对, 这 j 对的和都 x 的方案数.

设有 Posib 满足 i.

则写出 f 的方程:

fi,j=fi1,j+fi1,j1(Posxani+1j+1)

因为我们只需要 fn,i, 所以对于二维数组, 用形如 fi 表示 fn,i.

fi 的方案中, 有 nia 还没有配对. 所以 ((ni)!)fi, 相当于将没有配对的 nia 随意配对, 记为 gi.

gi=((ni)!)fi

因为已经有 ix, 剩下 ni 对不知道是否 x, 所以 gi 表示的方案中, 至少有 ix.

但是这时对于实际有 p 个对 x 的方案, p 对中有 i 对是一开始强制 x 的, 所以这个方案的 px 的元素, 任何一个大小为 i 的子集都会使它在 gi 中会被统计 1 次. 所以这个方案一共被统计了 (pj) 次.

hi 表示恰好 ix 的方案数.

根据定义容易写出式子:

gi=j=inhj(ji)

符合二项式反演公式, 所以可以求 h:

hj=i=jn(1)ij(ij)gi

接下来考虑求 x 为第 k 大的数的情况数.

j=inhj 表示至少有 ix 的方案数.

hi 中的方案分成两种情况, 第 k 大的是 x 和第 k 大的 <x.

前一种情况需要统计, 后一种需要舍弃.

因为 x 为第 k 大的方案中, 一定至少有 nk+1x, 所以 j=nk+1nhj 一定包含了所有要统计的情况.

接下来考虑如何去掉剩下的情况.

x1 那一轮的 h 数组为 h.

发现 j=inhj 里统计的所有情况, 都会被 j=inhj 包含, 因为至少 i<x 的方案中, x 的对数肯定不会更少, 也就是说所有这些方案中 x 的对数不会少于 i, 都会被 j=inhj 统计.

j=nk+1nhj 的第 k 大的数一定 <x, 所以这些方案都应该被舍弃.

而所有应该被舍弃的方案中, 都有至少 nk+1<x, 所以 j=nk+1nhj 包含了所有需要被舍弃的方案.

因此, x 为第 k 大的数的所有情况应该是

i=nk+1nhii=nk+1nhi=i=nk+1n(hihi)

const unsigned long long Mod(1000000007);
unsigned long long Fac[405], Inv[405], Pow, Poi(Mod - 2);
unsigned long long Cnt(0), Ans(0);
unsigned long long C[405][405];// Binom
unsigned long long DP[405]; // chosed i pairs to <= x 
unsigned long long f[405];  // x = x - 1, h
unsigned long long g[405];  // at least i pairs <= x
unsigned long long h[405];  // i pairs  <= x
unsigned a[405], b[405], Pos[805], m, n;
unsigned MA(0), MB(0), A, B;
char Flg (0);
signed main() {
  n = RD(), m = RD(), Inv[n] = Fac[0] = 1;
  for (unsigned i(1); i <= n; ++i) MA = max(a[i] = RD(), MA);
  for (unsigned i(1); i <= n; ++i) MB = max(b[i] = RD(), MB);
  sort(a + 1, a + n + 1);
  sort(b + 1, b + n + 1);
  MA += MB;
  for (unsigned i(1); i <= n; ++i) Fac[i] = Fac[i - 1] * i % Mod;
  Pow = Fac[n]; while (Poi) {if(Poi & 1) Inv[n] = Inv[n] * Pow % Mod; Poi >>= 1, Pow = Pow * Pow % Mod;}
  for (unsigned i(n - 1); ~i; --i) Inv[i] = Inv[i + 1] * (i + 1) % Mod;
  b[n + 1] = 0x3f3f3f3f;
  for (unsigned i(1), j(1); i <= n; ++i)
    while (j < b[i]) Pos[j++] = i - 1;
  for (unsigned i(MA); !(Pos[i]); --i) Pos[i] = n;
  for (unsigned i(1); i <= n; ++i) {
    C[i][0] = C[i][i] = 1;
    for (unsigned j(1); j < i; ++j){
      C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
      if(C[i][j] >= Mod) C[i][j] -= Mod;
    }
  }
  m = n - m + 1;
  for (unsigned x(1); x <= MA; ++x) {
    memset(DP, 0, sizeof(DP));
    memcpy(f, h, sizeof(h));
    Cnt = 0, DP[0] = 1;
    for (unsigned i(1); i <= n; ++i)
      for (unsigned j(i); j; --j)
        if((x > a[n - i + 1]) && (Pos[x - a[n - i + 1]] >= j))
          DP[j] = (DP[j] + DP[j - 1] * (Pos[x - a[n - i + 1]] - j + 1)) % Mod;
    for (unsigned i(1); i <= n; ++i) g[i] = DP[i] * Fac[n - i] % Mod;
    memset(h, 0, sizeof(h));
    for (unsigned i(1); i <= n; ++i)
      for (unsigned j(i); j <= n; ++j)
        if((j + i) & 1) {h[i] = (h[i] + Mod - ((C[j][i] * g[j]) % Mod)); if(h[i] >= Mod) h[i] -= Mod;}
        else h[i] = (h[i] + C[j][i] * g[j]) % Mod;
    for (unsigned i(m); i <= n; ++i) {
      Cnt += Mod + h[i] - f[i];
      while(Cnt >= Mod) Cnt -= Mod;
    }
    Ans = (Ans + Cnt * x) % Mod;
  }
  Ans = Ans * Inv[n] % Mod;
  printf("%llu\n", Ans);
  return Wild_Donkey;
}

证明

二项式反演中最常用的式子, 以下两式可互推:

fi=j=in(ji)gjgi=j=in(1)ji(ji)fj

其中, fi 一般表示用 DP 求出的, 在 n 个元素中, 至少 i 个元素满足某条件的方案数, 但是因为计算过程会将实际有 p 个元素满足条件的方案计算 (pi) 次.

gi 则表示恰有 i 个元素满足某条件, 没有重复统计的方案数.

所以一般我们需要做的就是通过上边的式子, 得到下面的式子, 用来给 fi 去重.

接下来假设已知上边的式子成立, 证明下面的式子.

根据上式, 知道 gi 的方案会在 fj 中统计 (ij) 次 (ji), 所以代入原式:

gi=j=in(1)ji(ji)(k=jn(kj)gk)gi=j=in(1)jij!i!(ji)!(k=jnk!j!(kj)!gk)gi=1i!j=in(1)ji1(ji)!(k=jnk!(kj)!gk)

k 放到外层循环.

gi=1i!k=ingkk!j=ik(1)ji(ji)!(kj)!

ki 是奇数的时候

j=ik(1)ji(ji)!(kj)!=j=0ki12(1)jj!(kij)!+(1)kji(kji)!j!=j=0ki12(1)j(1j!(kij)!+(1)k2ji(kji)!j!)=j=0ki12(1)j(1+(1)k2ji)j!(kij)!=j=0ki12(1)j(1+(1)ki)j!(kij)!=j=0ki12(1)j(11)j!(kij)!=0

所以, 满足 ki 是奇数的 gk 不会被统计到 gi 中.

如果 ki 是偶数.

j=ik(1)ji(ji)!(kj)!=(1)ki2(ki2)!(kk+i2)!+j=0ki212(1)jj!(kij)!=(1)ki2((ki2)!)2+j=0ki212(1)jj!(kij)!=(1)ki2((ki2)!)2+2j=0ki21(1)jj!(kij)!

草化不动了, 打表发现这个式子在 ki2 的时候都是 0, 综上, 所有 k>igk 都不会统计到 gi 中.

对于 gi, 有:

1i!gii!(1)01=gi

所以最后只剩一个 gi, 等式两边相等, 定理得证.

posted @   Wild_Donkey  阅读(58)  评论(1编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示