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;
}