2020杭电多校第10场1004

题意:给你一个长度为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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43916777/article/details/108402879