#182. 数集合

来源:互联网 发布:大数据架构师年龄要求 编辑:程序博客网 时间:2024/05/16 19:44

蒟蒻教你如何爆零:这种dp题,自己想的时候怎么都是错的,越想越复杂,看了答案后又顿时觉得,TM就是到水题。

用f[i][j]表示n=i,k=j时的答案。显然j≤i。

通过看题解,我们知道,f[i][j]必由f[h][j-1]转移过来,h=1...n,又h≥j-1,所以令h=j-1...n。

先考虑有效区间,其左端点必>h,为了做到不重不漏,令其左端点为h+1,得到共i-h个区间,这些区间可以随便选,但不能都不选,所以有2^(i-h)-1种选法。

再考虑无效区间,必定是左端点≤h,右端点大于h,这些区间随机选,可以都不选,共2^(h*(i-h))种选法。

代码短的可以:

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>using namespace std;#define rep(i,j,k) for(i=j;i<=k;++i)#define per(i,j,k) for(i=j;i>=k;--i)#define ll long long#define ldb long double#define pii pair<int,int>#define mkp make_pair#define X first#define Y secondconst ll N=505,MOD=1000000007;ll n,k,f[N][N],pw2[N*N];int main(){ll i,j,h;scanf("%lld%lld",&n,&k);pw2[0]=1;rep(i,1,n*n)pw2[i]=(pw2[i-1]<<1)%MOD;rep(i,0,n)f[i][0]=1;rep(i,1,n)rep(j,1,k)rep(h,j-1,i)f[i][j]=(f[i][j]+f[h][j-1]*(pw2[i-h]-1)%MOD*pw2[h*(i-h)])%MOD;printf("%lld\n",f[n][k]);return 0;}


0 0