题目大意:给出一个长度为n的序列A(A1,A2…AN)。如果序列A不是非降的,你必须从中删去一个数,这一操作,直到A非降为止。求有多少种不同的操作方案,答案模10^9+7
题解:f[i][j]表示选取到第i个元素,第i个元素必须选,一共选出了j个元素,选出的元素构成一个不降的子序列的方案数
树状数组dp一下就
O(n2logn)
了
记g[i]为长度为j的不下降子序列个数, gi=∑j=inf[j][i]
容易想到枚举长度i, ans+=(n−i)!∗f[i]
但是这样可能会有一些不合法的方案
注意到不合法的方案在最后一步删之前是一个长度为i+1的不下降子序列,那么不合法的方案数为 (n−i−1)!∗f[i+1]∗(i+1)
我的收获:吼啊!
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2005;
const int P=1000000007;
int n;
int a[N],z[N];
ll f[N][N],g[N],fac[N],s[N][N];
inline void add(int id,int pos,ll x)
{
for(;pos<=n;pos+=(pos&(-pos))) (s[id][pos]+=x)%=P;
}
inline ll query(int id,int pos)
{
ll ans=0;
for(;pos;pos-=(pos&(-pos))) (ans+=s[id][pos])%=P;
return ans;
}
void work()
{
add(0,1,1);
for(int i=1;i<=n;i++) for(int j=i;j>=1;j--)
{
f[i][j]=query(j-1,a[i])%P;
add(j,a[i],f[i][j]);
}
for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) (g[i]+=f[j][i])%=P;
ll ans=0;
for(int i=1;i<=n;i++) ans=(((ans+g[i]*fac[n-i])%P-g[i+1]*fac[n-i-1]%P*(i+1)%P)%P+P)%P;
printf("%lld\n",ans);
}
void init()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),z[i]=a[i];
sort(z+1,z+1+n);int cnt=unique(z+1,z+1+n)-z-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(z+1,z+1+cnt,a[i])-z;
fac[0]=1;for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;
}
int main()
{
init();
work();
return 0;
}