题目大意
有n个数,让你对其排列,令排列后的第i个数字为sis_isi,该排列要满足:
- ∀i∈[1,n),si≤si+1\forall i\in [1,n),s_i\leq s_{i+1}∀i∈[1,n),si≤si+1
- ∀i∈[1,n),∣(min(si,si+1),max(si,si+1))∩{sj∣k>i}∣≤bi\forall i\in [1,n),\begin{vmatrix}(min(s_i,s_{i+1}),max(s_i,s_{i+1}))\cap \{s_j| k>i\}\end{vmatrix}\leq b_i∀i∈[1,n),∣∣(min(si,si+1),max(si,si+1))∩{sj∣k>i}∣∣≤bi
输出方案数
解题思路
设fs,if_{s,i}fs,i为状态为s,最后一个数为i的方案数
那么每次选择一个可行的点转移,最后取所有点都排列好的状态即可
code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 20
#define M 263000
#define wyc 4921057
using namespace std;
int n,num,now,ans,a[N],b[N],v[N],f[M][N];
int main()
{scanf("%d",&n);for(int i=1;i<=n;++i){scanf("%d",&a[i]);v[a[i]]++;}for(int i=1;i<=n;++i)scanf("%d",&b[i]);for(int i=2;i<=10;++i)v[i]+=v[i-1];for(int i=1;i<=n;++i)if(!v[a[i]-1])f[1<<i-1][i]=1;for(int s=1;s<(1<<n)-1;++s){num=0;for(int i=1;i<=n;++i)if(s&(1<<i-1))num++;for(int i=1;i<=n;++i)if(s&(1<<i-1)&&f[s][i]){now=0;for(int j=i+1;j<=n&&now<=b[i];++j)if(!(s&(1<<j-1))){if(a[j]==a[i]||a[j]>a[i]&&num==v[a[i]])(f[s|(1<<j-1)][j]+=f[s][i])%=wyc;now++;}now=0;for(int j=i-1;j>0&&now<=b[i];--j)if(!(s&(1<<j-1))){if(a[j]==a[i]||a[j]>a[i]&&num==v[a[i]])(f[s|(1<<j-1)][j]+=f[s][i])%=wyc;now++;}}}for(int i=1;i<=n;++i)(ans+=f[(1<<n)-1][i])%=wyc;;printf("%d",ans);return 0;
}