SRM517-600加强版(DP)

题面

给定一个{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 取模。

Solution

考虑每一个i与p[i]是什么关系,就是说如果i<p[i],那么就是要向右交换。
然后对于两个点之间的交换一定是唯一的,也就是只经过一次。
所以就可以把每一个交换的方向(Theta(O(n^2)))的解决然后DP就好了。
注意前缀和优化Dp

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<queue>
#include<algorithm>
#define ll long long
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
using namespace std;
inline int gi(){
	int sum=0,f=1;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
inline ll gl(){
	ll sum=0,f=1;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
int o[10010];
ll f[5010][5010],g[5010][5010],ans;
vector<int>p;
const int Mod=1e9+7;
int main(){
	file("swap");
    int i,j,k,n,m;
	n=gi();
	for(i=0;i<n;i++){
		int x=gi();
		p.push_back(x);
	}
	n=p.size();
	memset(o,-1,sizeof(o));
	for(i=0;i<n;i++)
		if(i<p[i]){
			if(i-1>=0){
				if(!o[i-1])return puts("0"),0;
				o[i-1]=1;
			}
			for(j=i;j<p[i]-1;j++)
				if(o[j]==1)return puts("0"),0;
				else o[j]=0;
			if(p[i]-1<=n-3){
				if(!o[p[i]-1])return puts("0"),0;
				o[p[i]-1]=1;
			}
		}
		else if(i>p[i]){
			if(p[i]-1>=0){
				if(o[p[i]-1]==1)return puts("0"),0;
				o[p[i]-1]=0;
			}
			for(j=p[i];j<i-1;j++)
				if(!o[j])return puts("0"),0;
				else o[j]=1;
			if(i-1<=n-3){
				if(o[i-1]==1)return puts("0"),0;
				o[i-1]=0;
			}	
		}
		else return puts("0"),0;
	f[0][1]=g[0][1]=1;
	for(i=1;i<n-1;i++)
		for(j=1;j<=i+1;j++){
			if(o[i-1]!=1)
				(f[i][j]+=g[i-1][j-1])%=Mod;
			if(o[i-1]!=0)
				(f[i][j]+=g[i-1][i]-g[i-1][j-1])%=Mod;
			g[i][j]=(g[i][j-1]+f[i][j])%Mod;
		}
	for(i=1;i<n;i++)
		(ans+=f[n-2][i])%=Mod;
	ans%=Mod;
	while(ans<0)ans+=Mod;
	printf("%lld
",ans%Mod);
	return 0;
}
原文地址:https://www.cnblogs.com/cjgjh/p/9798940.html