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; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚