BZOJ 4824 [Cqoi2017]老C的键盘 ——树形DP
每一个限制条件相当于一条有向边,
忽略边的方向,就成了一道裸的树形DP题
同BZOJ3167
唯一的区别就是这个$O(n^3)$能过
#include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (ll i=j;i<=k;++i) #define D(i,j,k) for (ll i=j;i>=k;--i) #define ll long long #define mp make_pair #define maxn 205 const ll md=1000000007; ll h[maxn],to[maxn],ne[maxn],en=0,n; ll lim[maxn],siz[maxn],tmp[maxn]; ll dp[maxn][maxn],c[maxn][maxn]; char s[maxn]; void add(ll a,ll b) {to[en]=b;ne[en]=h[a];h[a]=en++;} ll C(ll n,ll m) { if (n<0||m<0) { return 0; } return c[n][m]; } void Tree_DP(ll o) { dp[o][1]=1;siz[o]=1; for (ll i=h[o];i>=0;i=ne[i]) { Tree_DP(to[i]); F(j,0,siz[o]+siz[to[i]]+2) tmp[j]=0; F(j,1,siz[o]) F(k,1,siz[to[i]]) F(_j,j,siz[to[i]]+siz[o]) if (dp[o][j]&&dp[to[i]][k]) { if (lim[to[i]]==1) { if (siz[o]+siz[to[i]]-_j>=siz[to[i]]-k+1+siz[o]-j&&_j>=j) { tmp[_j]+=(((ll)dp[o][j]*dp[to[i]][k])%md*C(_j-1,j-1))%md*C(siz[o]+siz[to[i]]-_j,siz[o]-j)%md; tmp[_j]%=md; } } else { if (_j>=j+k&&siz[o]+siz[to[i]]-_j>=siz[o]-j) { tmp[_j]+=(((ll)dp[o][j]*dp[to[i]][k])%md*C(_j-1,j-1))%md*C(siz[o]+siz[to[i]]-_j,siz[o]-j)%md; tmp[_j]%=md; } } } siz[o]+=siz[to[i]]; F(j,0,siz[o]) dp[o][j]=tmp[j]; } } void Finout() { freopen("in.txt","r",stdin); freopen("wa.txt","w",stdout); } int main() { memset(h,-1,sizeof h); scanf("%lld",&n); scanf("%s",s+2); c[1][0]=1;c[1][1]=1;c[0][0]=1; F(i,2,maxn-1) { c[i][0]=1; F(j,1,maxn-1) c[i][j]=(c[i-1][j]+c[i-1][j-1])%md; } F(i,2,n) { add(i/2,i); switch(s[i]) { case '<': lim[i]=1; break; case '>': lim[i]=-1;break; } } Tree_DP(1); ll ans=0; F(i,0,n) (ans+=dp[1][i])%=md; printf("%lld\n",ans); }