【交换】

【题目描述】

给定一个{0, 1, 2, 3, … , n - 1}的排列 p。一个{0, 1, 2 , … , n - 2}的排列q被认为是优美的排列,当且仅当q满足下列条件:

对排列s = {0, 1, 2, 3, ..., n - 1}进行n – 1次交换。

1. 交换s[q0],s[q0 + 1]

2. 交换s[q1],s[q1 + 1]

最后能使得排列s = p.

问有多少个优美的排列,答案对10^9+7取模。

【输入格式】

第一行一个正整数n.

第二行n个整数代表排列p.

【输出格式】

仅一行表示答案。

【样例输入】

3

1 2 0

【样例输出】

1

【样例解释】

q = {0,1} {0,1,2} ->{1,0,2} -> {1, 2, 0}

q = {1,0} {0,1,2} ->{0,2,1} -> {2, 0, 1}

【数据范围】

30%:  n <= 10

100%:  n <= 50

题解:
      ①顺着思考很麻烦,逆向考虑:最后一次交换发生的位置

      ②倒过来后,记忆化搜索,枚举当前状态的交换发生在哪个位置,然后区间一分为二处理子问题

      ③注意事项:交换可以发生的位置是左边和右边两部分都含有其应该有的数(顺序乱也可以)

      ④转移方程式:f[l][r]+=DFS(l,i)*DFS(i+1,r)*C[r-l-1][i-l]

            表示当前区间为[l,r],交换i,i+1,由于两边独立决策,所以存在一个组合关系,可以转化为有2n个空位放n个数的方案数,这样是因为每一边内部是有序的(这是一个重要结论)。

f[l][r]+=(((DFS(l,i)*DFS(i+1,r))%M*C[r-l-1][i-l])%M))%#include<stdio.h>
#define ll long long
#define M 1000000007
#define S(x,y) (x^=y^=x^=y)
#define go(i,a,b) for(int i=a;i<=b;i++)
const int N=55;int n,a[N],can;ll C[N][N],f[N][N];
ll DFS(int l,int r)
{
	if(l==r)return f[l][r]=1;
	if(f[l][r]>-1)return f[l][r];f[l][r]=0;
	go(i,l,r-1)
	{
		S(a[i],a[i+1]);can=1;
		if(can)go(j,l,i)if(a[j]<l||a[j]>i){can=0;break;}
		if(can)go(j,i+1,r)if(a[j]<i+1||a[j]>r){can=0;break;}
		if(can)(f[l][r]+=(((DFS(l,i)*DFS(i+1,r))%M*C[r-l-1][i-l])%M))%=M;
		S(a[i],a[i+1]);
	}
	return f[l][r];
}
int main()
{
	scanf("%d",&n);
	go(i,1,n){scanf("%d",a+i),a[i]++;go(j,1,n)f[i][j]=-1;}
	go(i,0,50){C[i][0]=1;go(j,1,i)C[i][j]=(C[i-1][j]+C[i-1][j-1])%M;}
	
	printf("%I64d
",(DFS(1,n)%M+M)%M);
	return 0;
}//Paul_Guderian

Life's a little bit messy. We all make mistakes.

No matter what type of animal you are, change starts with you.————Judy·Hopps

原文地址:https://www.cnblogs.com/Damitu/p/7646694.html