题目
求的排列,有
个限制条件,第
个限制条件
,
表示前个数不能是
的排列,求符合要求的排列的个数。
分析
这里是单纯计数的做法,时间复杂度
设表示前
个数均
并且必须包含
的方案数,
初始化(如果第一个数有限制要特判),最后输出
首先可以写出一个朴素的方程,
$i-1
j
1\sim j
j-i+1
j
j
j
dp[i][i]=0
O(n^3)
O(n^2)
n
m$还是原来的数据范围的话会直接T飞,但是数据还是很良心的
代码
#include <cstdio> #include <cctype> #include <algorithm> #define rr register using namespace std; const int mod=20000311,N=2011; int n,m,a[N],dp[N][N]; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;} signed main(){ n=iut(),m=iut(); for (rr int i=1;i<=m;++i) a[i]=iut(); for (rr int i=1;i<=n;++i) dp[1][i]=1; sort(a+1,a+1+m); for (rr int i=1,I=1;i<=n;++i){ rr int sum=dp[i-1][i-1]; if (i>1) for (rr int j=i;j<=n;++j) dp[i][j]=mo(sum,1ll*dp[i-1][j]*(j-i+1)%mod), sum=mo(sum,dp[i-1][j]); if (a[I]==i) dp[i][i]=0,++I; } return !printf("%d",dp[n][n]); }