BZOJ4475[Jsoi2015]子集选取——递推(结论题)

题目描述

输入

输入包含一行两个整数N和K,1<=N,K<=10^9

输出

一行一个整数,表示不同方案数目模1,000,000,007的值。

样例输入

2 2

样例输出

16
 
可以发现对于集合中每个元素的选取都是互不影响的,设$f(n,k)$为输入$n,k$时的答案,那么$f(n,k)=f(1,k)^n$。
我们现在来推导$f(1,k)$的结果:可以发现$1$的位置一定是连续的,设$a_{i}$表示第$i$列最后选取到了$a_{i}$行,若从第$1$列到第$m$列均存在被选取。
那么可以得到结论:$a_{i+1}\le a_{i}(1\le i <m)$。
设$g[i][j]$表示只有前$i$列有$1$,其中第$i$列最后选取到了第$j$行的方案数,可以得到递推式:$g[i][j]=\sum\limits_{p=j}^{k}g[i-1][p]$。
通过观察可以得到:$g[i][j]=g[i-1][j]+g[i][j+1]$,这实际上就是一个顺时针旋转了$45^{\circ}$的杨辉三角。
那么加上都不选取的方案数为$1$,$f(1,k)=1+\sum g[i][j]=2^k$,由此可得$f(n,k)=2^{nk}$。
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int n,k;
int mod=1000000007;
ll quick(ll x,ll y)
{
	ll res=1;
	while(y!=0)
	{
		if(y%2==1)
		{
			res=(res*x)%mod;
		}
		x=(x*x)%mod;
		y/=2;
	}
	return res%mod;
}
int main()
{
	scanf("%d%lld",&n,&k);
	ll sum=1ll*n*k;
	printf("%lld",quick(2,sum));
}
posted @ 2019-03-02 11:16  The_Virtuoso  阅读(314)  评论(0编辑  收藏  举报