51nod-1296: 有限制的排列

【传送门:51nod-1296


简要题意:

  有一个集合,集合中的数为1到n

  给出a限制条件,a[i]表示第a[i]位置的数要比相邻位置的数要小

  给出b限制条件,b[i]表示第b[i]位置的数要比相邻位置的数要大

  求出符合条件的序列个数


题解:

  DP

  设f[i][j]为i位数,最后一位为j的情况数

  我们要将j合理的放在末尾,那么可以把前面>=j的数都+1,这样就能空出j这个数来了

  设p[i]为第i个位置的限制条件,p[i]=-1表示第i个位置小于第i-1个位置,p[i]=1则是大于,p[i]=0表示无限制条件

  为了能更好的转移,设$s[j]=\sum_{k=1}^{j}f[i-1][k]$

  分三种情况转移即可


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
int p[5100];
int f[5100][5100],s[5100];
int Mod=1e9+7;
int main()
{
    int n,k,l;
    scanf("%d%d%d",&n,&k,&l);
    bool bk=false;
    for(int i=1;i<=k;i++)
    {
        int x;
        scanf("%d",&x);x++;
        if(p[x]==1) bk=true;
        p[x]=-1;
        if(x+1>n) continue;
        if(p[x+1]==-1) bk=true;
        p[x+1]=1;
    }
    for(int i=1;i<=l;i++)
    {
        int x;
        scanf("%d",&x);x++;
        if(p[x]==-1) bk=true;
        p[x]=1;
        if(x+1>n) continue;
        if(p[x+1]==1) bk=true;
        p[x+1]=-1;
    }
    if(bk==true){printf("0\n");return 0;}
    f[1][1]=1;
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<i;j++) s[j]=((LL)s[j-1]+(LL)f[i-1][j])%Mod;
        for(int j=1;j<=i;j++)
        {
            if(p[i]==1) f[i][j]=s[j-1];
            else if(p[i]==-1) f[i][j]=((LL)s[i-1]-(LL)s[j-1]+(LL)Mod)%Mod;
            else f[i][j]=s[i-1];
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++) ans=((LL)ans+(LL)f[n][i])%Mod;
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-10-11 12:40  Star_Feel  阅读(295)  评论(0编辑  收藏  举报