swap

我们将s转化成p可以换过来,把p换成s是一样的。
对于一个位置p[i],我们可以知道他最后的位置会在哪,所以我们可以连锁的知道从i转换到p[i]这一路上每一次交换的先后顺序。当我们知道每一个交换的先后顺序后,我们可以令pos[i]为交换[i,i+1]在q里的位置。那么对于每一对pos[i]和pos[i+1],我们都可以知道他们的相互关系是大于还是小于。
设comp[i]表示pos[i]与pos[i+1]的关系,等于2表示pos[i]>pos[i+1],等于1表示小于。
求comp数组代码:

bool make_comp() {
	for(int i=0;i<n;i++) {
		if(p[i]==i)return 0;//因为每一个位置都会换,所以存在p[i]=i的话就不合法了
		if(p[i]>i) {//若当前位置会往后面移动,那么交换i到p[i]-1都会从先到后依次执行
			if(i-1>=0) {
				if(comp[i-1]==1)return 0;//但是i-1必须在i换完之后再换,否则会把p[i]换到前面去,就GG了
				else comp[i-1]=2;
			}
			for(int j=i;j<p[i]-1;j++)
				if(comp[j]==2)return 0;
				else comp[j]=1;//j在j+1前面
			if(p[i]-1<=n-3) {
				if(comp[p[i]-1]==1)return 0;//p[i]-1必须要比p[i]后换,不然p[i]就位之后被换走了就回不来了就GG了
				else comp[p[i]-1]=2;
			}
		}
		else {//当p[i]要往前移动是一样的。
			if(p[i]-1>=0) {
				if(comp[p[i]-1]==2)return 0;
				else comp[p[i]-1]=1;
			}
			for(int j=p[i];j<i-1;j++)
				if(comp[j]==1)return 0;
				else comp[j]=2;
			if(i-1<=n-3) {
				if(comp[i-1]==2)return 0;
				else comp[i-1]=1;
			}
		}
	}
	return 1;
}

然后我们把comp数组求出来后就可以dp求q数组方案数了
代码如下:

#include <cstdio>
using namespace std;

const int pps=1e9+7,maxn=5005;

int n,ans;
int p[maxn],comp[maxn];
int f[maxn][maxn],g[maxn][maxn];

int read() {
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	return x*f;
}

bool make_comp() {
	for(int i=0;i<n;i++) {
		if(p[i]==i)return 0;
		if(p[i]>i) {
			if(i-1>=0) {
				if(comp[i-1]==1)return 0;
				else comp[i-1]=2;
			}
			for(int j=i;j<p[i]-1;j++)
				if(comp[j]==2)return 0;
				else comp[j]=1;
			if(p[i]-1<=n-3) {
				if(comp[p[i]-1]==1)return 0;
				else comp[p[i]-1]=2;
			}
		}
		else {
			if(p[i]-1>=0) {
				if(comp[p[i]-1]==2)return 0;
				else comp[p[i]-1]=1;
			}
			for(int j=p[i];j<i-1;j++)
				if(comp[j]==1)return 0;
				else comp[j]=2;
			if(i-1<=n-3) {
				if(comp[i-1]==2)return 0;
				else comp[i-1]=1;
			}
		}
	}
	return 1;
}

void dp() {
	f[0][1]=g[0][1]=1;
	for(int i=1;i<=n-2;i++)
		for(int j=1;j<=i+1;j++) {
			if(comp[i-1]==1)f[i][j]=(f[i][j]+g[i-1][j-1])%pps;
			if(comp[i-1]==2)f[i][j]=(f[i][j]+g[i-1][i]-g[i-1][j-1])%pps;
			f[i][j]=(f[i][j]%pps+pps)%pps;g[i][j]=(g[i][j-1]+f[i][j])%pps;
		}
}

int main() {
	n=read();
	for(int i=0;i<n;i++)
		p[i]=read();
	if(!make_comp()){puts("0");return 0;}
	dp();
	for(int i=1;i<=n-1;i++)
		ans=(ans+f[n-2][i])%pps;
	printf("%d\n",ans);
	return 0;
}

posted on 2018-10-16 19:35  HYSBZ_mzf  阅读(353)  评论(0编辑  收藏  举报

导航