BZOJ4475 [Jsoi2015]子集选取

Description

有一些\(\{1\dots n\}\)的子集\(A_{i,j}, 1\leq j\leq i\leq 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\leq 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;
}
posted @ 2018-03-06 09:46  _rqy  阅读(196)  评论(0编辑  收藏  举报