题意:给你一个长度为n-1的序列,若a[i]=1,则b[i]>b[i+1];若a[i]=0,则b[i]<b[i+1]。问你根据这个给定的a序列能构造成多少满足条件的关于b的全排列。
思路:dp[i][j]表示放了i个数,第i个位置放j的情况总数。假如现在放到第i个位置,想要在第i个位置放置j。若a[i]=0,那么dp[i][j]=dp[i-1][1]+dp[i-1][2]+…+dp[i][j-1]。这里有一个问题,那就是会想到重复放置数的情况。比如,现在要放3,而前面已经放过。前一个集合为{1,3,2},那么变成{1,3,2,3}。我们可以将前面大于3的数都加1,那么就变成了{1,4,2,3},这样就满足了条件。所以也就没有重复放置数的问题了。若a[i]=1,那么dp[i][j]=dp[i-1][j]+dp[i-1][j+1]+dp[i-1][i-1],关于重复放置情况的分析与上面类似。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll T,n,a[5005],qz[5005],dp[5005][5005];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;
for(ll i=2;i<=n;i++) cin>>a[i];
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
dp[i][j]=qz[j]=0;
dp[1][1]=1;qz[1]=1;
for(ll i=2;i<=n;i++){
for(ll j=1;j<=i;j++){
if(!a[i]) dp[i][j]=(dp[i][j]+qz[j-1])%mod;
if(a[i]) dp[i][j]=(dp[i][j]+qz[i-1]-qz[j-1])%mod;
}
qz[1]=0;
for(ll j=1;j<=i;j++){
qz[j]=(qz[j-1]+dp[i][j])%mod;
}
}
ll sum=0;
for(ll i=1;i<=n;i++) sum=(sum+dp[n][i])%mod;
cout<<(sum+mod)%mod<<endl;
}
return 0;
}