2020杭电多校第10场1004

tech2025-11-26  28

题意:给你一个长度为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; }
最新回复(0)