BZOJ4475 [JSOI2015] 子集选取

2018 年 03 月 14 日发布.

Description

有一些$\{1\dots n\}$的子集$A_{i,j}, 1\leqslant j\leqslant i\leqslant k$共$\frac{k(k+1)}2$个,满足$A_{i,j}\subset A_{i+1,j}, A_{i,j}\subset A_{i,j+1}$。求这些集合有多少种方案。如果$A$和$B$两种方案中存在$i,j$使得$A_{i,j}\neq B_{i,j}$,则它们是不同的。$n, k\leqslant 10^9$

Solution

对于$n=1$求出方案数,之后将这个方案数取$n$次幂即可。因为不同的元素之间是互不影响的。

$n=1$时,我实际上要从 $$ \begin{matrix} A_{1,1}\\ A_{2,1}&A_{2,2}\\ A_{3,1}&A_{3,2}&A_{3,3}\\ \vdots&\vdots&\vdots&\ddots\\ A_{k,1}&A_{k,2}&A_{k,3}&\cdots&A_{k,k} \end{matrix} $$ 这个三角中选出一些来包含$1$。

那么,我从这个矩阵左下角即$A_{k,1}$的左下方开始,每次向右或上走一步,直到某个$A_{i,i}$的左上角(或者$A_{k,k}$的右下角);走出这个折线的右下的集合包含$1$,其它不包含$1$。那么我一共会走$(k-i+1)+(i-1)=k$步,每步可以向右/下走,所以共有$2^k$种方案。

综上,答案即为$2^{nk}$。

Code

#include <cstdio>
typedef long long LL;
const int mod = 1000000007;
int main() {
  int n, k;
  scanf("%d%d", &n, &k);
  int ans = 1, x = 2;
  for (n = (LL)n * k % (mod - 1); n; n >>= 1, x = (LL)x * x % mod)
    if (n & 1) ans = (LL)ans * x % mod;
  return printf("%d\n", ans) & 0;
}