这道题可以说是对 d p dp dp的考察非常特别
好题,但是我是废物,一种做法都没想到
Ⅰ . 考 虑 到 前 i 个 数 不 能 是 [ 1 , i ] 的 排 列 \color{Red}Ⅰ.考虑到前i个数不能是[1,i]的排列 Ⅰ.考虑到前i个数不能是[1,i]的排列
等 价 于 前 i 个 数 出 现 过 大 于 i 的 数 字 等价于前i个数出现过大于i的数字 等价于前i个数出现过大于i的数字
定 义 d p [ i ] [ j ] 为 前 i 个 数 字 种 最 大 是 j 的 排 列 数 字 定义dp[i][j]为前i个数字种最大是j的排列数字 定义dp[i][j]为前i个数字种最大是j的排列数字
转移是 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] ∗ ( i − j + 1 ) + p r e [ j − 1 ] dp[i][j]=dp[i-1][j]*(i-j+1)+pre[j-1] dp[i][j]=dp[i−1][j]∗(i−j+1)+pre[j−1]
p r e [ j − 1 ] = ∑ i = 1 j − 1 d p [ i − 1 ] [ i ] pre[j-1]=\sum\limits_{i=1}^{j-1}dp[i-1][i] pre[j−1]=i=1∑j−1dp[i−1][i]
这部分表示若前 i − 1 i-1 i−1个数字不大于 j j j,现在就可以放数字 j j j来转移
d p [ i − 1 ] [ j ] ∗ ( j − i + 1 ) dp[i-1][j]*(j-i+1) dp[i−1][j]∗(j−i+1)
这部分表示若前 i − 1 i-1 i−1个数的最大值是 j j j,说明还有 j − ( i − 1 ) j-(i-1) j−(i−1)个小于 j j j的没用过
这样最后 d p [ n ] [ n ] dp[n][n] dp[n][n]就是答案
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2009;
const int mod=20000311;
int p[maxn],dp[maxn][maxn],pre[maxn];
signed main()
{
int n,m;
cin >> n >> m;
for(int i=1;i<=m;i++) cin >> p[i];
memset(dp,-1,sizeof(dp));
for(int i=1;i<=n;i++) dp[1][i]=1;
for(int i=1;i<=m;i++) dp[p[i]][p[i]]=0;
for(int i=1;i<=n;i++) pre[i]=pre[i-1]+dp[1][i];
for(int i=2;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if( dp[i][j]==0 ) continue;
if( i>j ) dp[i][j]=0;
else
dp[i][j] = ( dp[i-1][j]*(j-i+1)+pre[j-1] )%mod;
}
for(int j=1;j<=n;j++)
pre[j] = (pre[j-1]+dp[i][j] )%mod;
}
printf("%lld",dp[n][n]);
}
第 二 种 做 法 是 一 维 的 , 也 很 巧 妙 \color{Red}第二种做法是一维的,也很巧妙 第二种做法是一维的,也很巧妙
定义 d p [ i ] dp[i] dp[i]是处理到第 p [ i ] p[i] p[i]个数,前 i − 1 i-1 i−1个限制满足条件,第 i i i个限制条件不满足
这样就可以做到不重不漏
最后用 n ! − ∑ i = 1 m d p [ i ] n!-\sum\limits_{i=1}^{m}dp[i] n!−i=1∑mdp[i]就是答案
d p [ 1 ] = f a c [ p [ 1 ] ] dp[1]=fac[p[1]] dp[1]=fac[p[1]]很明显,就是 [ 1 , p [ 1 ] ] [1,p[1]] [1,p[1]]的全排列
那么 d p [ 2 ] = f a c [ p [ 2 ] ] dp[2]=fac[p[2]] dp[2]=fac[p[2]]对吗?算多了,需要减掉在第一个限制条件就不满足的情况
就是 d p [ 2 ] = f a c [ p [ 2 ] ] − d p [ 1 ] ∗ f a c [ p [ 2 ] − p [ 1 ] ] dp[2]=fac[p[2]]-dp[1]*fac[p[2]-p[1]] dp[2]=fac[p[2]]−dp[1]∗fac[p[2]−p[1]]
意思是 [ 1 , p [ 1 ] ] [1,p[1]] [1,p[1]]的数字仍然在 [ 1 , p [ i ] ] [1,p[i]] [1,p[i]]位置,余下来的位置随便排列
接下来就是一样的道理了
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2009;
const int mod=20000311;
int dp[maxn],p[maxn],fac[maxn];
signed main()
{
int n,m;
cin >> n >> m;
for(int i=1;i<=m;i++) cin >> 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);
dp[1]=fac[p[1]];
for(int i=2;i<=m;i++)
{
dp[i]=fac[p[i]];
for(int j=1;j<i;j++)
dp[i] = ( dp[i]-dp[j]*fac[p[i]-p[j]] )%mod;
}
int ans=fac[n];
for(int i=1;i<=m;i++) ans = ( ans-dp[i]*fac[n-p[i]] )%mod;
cout << ( ans%mod+mod )%mod;
}