标签: return int 交换 long include dp
给定一个\(0∼n−1\)的排列\(p\)。一个\(0∼n−2\)的排列q被认为是优美的,当且仅当满足下列条件:
对排列\(s=\{0,1,2⋯,n−1\}\)进行n–1次交换。(下标从0开始)
交换\(s[q_0],s[q_0+1]\)
交换s\([q_1],s[q_1+1]\)
⋯
最后能使得排列\(s=p\)。 问有多少个优美的排列,答案对\(10^9+7\)取模。
输入格式
第一行一个整数\(n\)。
接下来一行\(n\)个数,第\(i\)个表示\(p_i\)
输出格式
一行一个整数,表示答案。
样例
样例一
input
3
1 2 0
output
1
约定与限制
对于\(30\%\) 的数据,满足 \(n≤10\)。
对于\(100\%\) 的数据 ,满足 \(1≤n≤50\) 。
时间限制:1s
空间限制:512MB
如果现在交换了\(i\)和\(j\)的位置,那么\(1~i\)和\(i~j\)两个区间之间不会再有交换,有区间dp的影子。所以我们交换这两个位置,然后递归数两个区间会有多少种情况能交换好。
定义\(dp_{i,j}\)为当交换出来后s数组由i到j的数都是大于等于i小于等于j时,有多少种情况使得i到j是排序好的。很容易证明,这个序列是唯一的。
边界情况:如果\(i=j\),那么只有一种情况。
我们枚举再次交换哪两个,如果交换\(k\)和\(k+1\),那么交换完判断\(i~k\)和\(k+1~j\)这两段是否合法,就是他们可以自己排序好自己。如果可以,那么答案加上\(dp_{i,k}\times dp_{k+1,j}\),但在序列中我们可以把他们的操作顺序打乱,所以再乘上\(C_{j-i+1}^{k-l}\)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=55,mod=1e9+7;
int n,a[N],f[N][N];
long long dp[N][N];
int can(int x,int y)
{
for(int i=x;i<=y;i++)
if(a[i]<x||a[i]>y)
return 0;
return 1;
}
long long dfs(int l,int r)
{
if(l==r)
return 1;
if(dp[l][r]!=-1)
return dp[l][r];
long long ret=0;
for(int i=l;i<r;i++)
{
swap(a[i],a[i+1]);
if(can(l,i))
ret=(ret+1LL*dfs(l,i)*dfs(i+1,r)%mod*f[r-l-1][i-l])%mod;
swap(a[i],a[i+1]);
}
return dp[l][r]=ret;
}
int main()
{
memset(dp,-1,sizeof(dp));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),++a[i];
for(int i=0 ;i<=n;i++)
{
f[i][0]=f[i][i]=1;
for(int j=1;j<i;j++)
f[i][j]=(f[i-1][j]+f[i-1][j-1])%mod;
}
printf("%lld",dfs(1,n));
}
标签:,return,int,交换,long,include,dp 来源: https://www.cnblogs.com/mekoszc/p/16148544.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。