ZR#1015
ZR#1015
解法:
我们需要求得, $ g_i $ 表示长度为的最长不下降子序列个数。
设 $ f_{i,j} $ 表示统计第前$ i $ 个数字,得到最长不下降子序列末端为 $ j $ 。
显然这个状态可以从前面所有转移过来。
树状数组优化一下。
考虑到在 $ g_i $ 状态下,我们可以以任意顺序删去个 $ n-i $ 数,则长度为 $ i $ 的最长不下降子序列方案数为 $ g_i(n - i) !$
但是,不能保证它在成为最长不下降子序列时就停止删数。
不合法方案数为 $ g_{i+1}(n- i - 1)! * (i + 1) $ (最后一次可以删个数中任意一个)。
所以统计答案的时候就是 $ ans = g_i * (n - i)! - g_{i+1}*(n-i-1)! * (i + 1) $
CODE:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
#define N 2010
const int mod = 1e9 + 7;
int n,pos[N];
LL a[N],t[N],sum[N][N];
LL f[N][N],g[N],fac[N],ans;
inline int lowbit(int x) {
return x & -x;
}
void update(int id,int x,LL v) {
for(int i = x ; i <= n ; i += lowbit(i))
sum[id][i] = (sum[id][i] + v) % mod;
}
LL query(int id,int x) {
LL ans = 0;
for(int i = x ; i ; i -= lowbit(i))
ans = (ans + sum[id][i]) % mod;
return ans;
}
int main() {
scanf("%d",&n);
for(int i = 1 ; i <= n ; i++)
scanf("%lld",&a[i]);
for(int i = 1 ; i <= n ; i++) t[i] = a[i];
sort(t + 1,t + n + 1);
int num = unique(t + 1,t + n + 1) - t - 1;
fac[1] = 1;
for(int i = 1 ; i <= n ; i++)
pos[i] = lower_bound(t + 1,t + num + 1,a[i]) - t;
for(int i = 2 ; i <= n ; i++)
fac[i] = 1LL * fac[i - 1] * i % mod;
update(0,1,1);
for(int i = 1 ; i <= n ; i++) {
for(int j = i ; j >= 1 ; j--) {
f[i][j] = (f[i][j] + query(j - 1,pos[i]) % mod) % mod;
update(j,pos[i],f[i][j] % mod);
}
}
for(int i = 1 ; i <= n ; i++) {
for(int j = 1 ; j <= n ; j++) {
g[i] = (g[i] + f[j][i]) % mod;
}
}
for(int i = 1 ; i <= n ; i++)
ans = ((ans % mod + (fac[n - i] % mod * g[i] % mod) % mod) % mod - fac[n - i - 1] % mod * g[i + 1] % mod * (i + 1) % mod + mod) % mod;
printf("%lld\n",ans);
//system("pause");
return 0;
}
有些路你和某人一起走,就长得离谱,你和另外一些人走,就短得让人舍不得迈开脚步。