蒟蒻教你如何爆零:这种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 second
const 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;
}