atcoder dp专题 T - Permutation
题意:
长度为n的全排列,给出长度为n-1字符串,只包含“<”和“>”,问有多少种排列方式,使得排列的数字大小满足给出的字符串。
题解:
dp[i][j]表示前i个数字为1-i的全排列并且第i个数字是j且满足大小关系的方案数,再设sum[i][j]。表示第i个位置放1~j的方案数之和,即前缀和,那么状态转移便是:
if(s[i]=='>')
{
dp[i+1][j]=(dp[i+1][j]+sum[i][i+1]-sum[i][j-1]+mod)%mod;
}
else
{
dp[i+1][j]=(dp[i+1][j]+sum[i][j-1])%mod;
}
为什么是这样呢,我们假设在i位置放入了j,那么前面大于等于j的数字加1,则必定保证这是全排列,所以当遇到’>’,我插入了j,那么就去找前面大于等于j的方案数,反之则是小于j。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define fi first
#define se second
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=3e3+5;
const int mod=1e9+7;
char s[MAXN];
ll dp[MAXN][MAXN];
ll sum[MAXN][MAXN];
int main()
{
int n;
scanf("%d",&n);
scanf("%s",s+1);
dp[1][1]=1;
sum[1][1]=1;
for(int i=2;i<=n;i++) sum[1][i]=sum[1][i-1];
for(int i=1;i<=n-1;i++)
{
for(int j=1;j<=i+1;j++)
{
if(s[i]=='>')
{
dp[i+1][j]=(dp[i+1][j]+sum[i][i+1]-sum[i][j-1]+mod)%mod;
}
else
{
dp[i+1][j]=(dp[i+1][j]+sum[i][j-1])%mod;
}
}
for(int j=1;j<=n;j++)
{
sum[i+1][j]=(sum[i+1][j-1]+dp[i+1][j])%mod;
}
}
ll ans=0;
for(int i=1;i<=n;i++)
{
//cout<<dp[n][i]<<endl;
ans=(ans+dp[n][i])%mod;
}
printf("%lld\n",ans);
}

浙公网安备 33010602011771号