码迷,mamicode.com
首页 > 其他好文 > 详细

毛二琛

时间:2018-10-16 19:54:31      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:int   cpp   clu   put   for   code   表示   space   cst   

我们将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;
}

毛二琛

标签:int   cpp   clu   put   for   code   表示   space   cst   

原文地址:https://www.cnblogs.com/Mly020220/p/9800136.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!