题意:求长度为n的排列有多少个 要求满足 m个条件 :pi 表示前pi个数不是1~pi的全排列
m<n<=2000
思路:
1️⃣:考虑用总方案数减去不符合条件的方案数:即对于位置 x 为,x! - (不符合条件)。设F[i]为前i-1个条件满足,第i个条件不满足的方案数,并且我们增加一项p[m+1]=n,那么F[m+1]即为答案
转移方程:F[i]=sigma(F[j]*(j-i)!)(1<=j<i)
第一次遇到这样的dp状态-_- 很奇妙。。 它是通过枚举最后一个不满足条件的位置来得到答案,所以不会减重复。学到了
2️⃣:常规dp,dp[i][j]表示第i个位置以及之前的数最大值为j的方案数,那么对于限制条件i我们只需要使dp[p[i]][p[i]]==0后正常转移即可
#include<bits/stdc++.h>
#define pb push_back
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long ll;
typedef vector<int> VI;
const int mod = 20000311;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6 + 4;
const int N = 405;
//ll qpow(ll x, ll y) {ll ans = 1; x %= mod; assert(y >= 0); while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod; y >>= 1;} return ans;}
//ctrl + h ctrl + shift + t
int n,m,p[maxn];
ll fac[maxn],f[maxn];
int main() {
//freopen("input.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d",&p[i]);
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
sort(p+1,p+1+m);
p[++m]=n;
for(int i=1;i<=m;i++) {
f[i]=fac[p[i]];
ll res=0;
for(int j=1;j<i;j++) res=(res+f[j]*fac[p[i]-p[j]])%mod;
f[i]=f[i]+mod-res;
f[i]%=mod;
}
printf("%lld\n",f[m]);
return 0;
}
#include<bits/stdc++.h>
#define pb push_back
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long ll;
typedef vector<int> VI;
const int mod = 20000311;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6 + 4;
const int N = 405;
//ll qpow(ll x, ll y) {ll ans = 1; x %= mod; assert(y >= 0); while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod; y >>= 1;} return ans;}
//ctrl + h ctrl + shift + t
int n,m,d,p[maxn],a[maxn];
ll fac[maxn],dp[2020][2020],sum[2020];
int main() {
//freopen("input.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d",&d),a[d]=1;
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
dp[0][0]=1;
for(int i=1;i<=n;i++) {
sum[0]=dp[i-1][0];
for(int j=1;j<=n;j++) sum[j]=(dp[i-1][j]+sum[j-1])%mod;
for(int j=i;j<=n;j++) {
dp[i][j]=dp[i-1][j]*(j-i+1)%mod;
ll k=0;
if(i>=2) k=sum[j-1]+mod-sum[i-2];
else k=sum[j-1];
dp[i][j]+=k;
dp[i][j]%=mod;
}
if(a[i]) dp[i][i]=0;
}
printf("%lld\n",dp[n][n]);
return 0;
}