强军战歌

  • Code Level: ※
  • Thinking Level: ※※

Description

给长为N的序列A,删数恰到A为非降序列,求删数方案

Solution

先思考大范围(即删出一个长为i的非降序列的方案数)

再通过删去误解得到合法解,即减去存在误删的方案数

因为一个合法的非降序列删去其内一个数任然是合法的序列,即强制构造达到一个合法序列再删除一个元素即可(这里对于删除多个元素的情况有一个小容斥)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int nn=2005;
const ll mod=1e9+7;
int n,m,a[nn],b[nn];
ll f[nn][nn],num[nn][nn],cnt[nn],jc[nn];
ll quert(int id,int x){
ll sum=0;
for(;x;x-=x&-x) (sum+=num[id][x])%=mod; return sum;
}
void updata(int id,int x,ll h){
for(;x<=m;x+=x&-x) (num[id][x]+=h)%=mod;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n); m=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+1+m,a[i])-b;
updata(0,1,1); jc[0]=1;
for(int i=1;i<=n;i++)
for(int j=i;j>0;j--){
f[i][j]=quert(j-1,a[i]); cnt[j]=(cnt[j]+f[i][j])%mod; //printf("%lld\n",cnt[j]);
updata(j,a[i],f[i][j]);
}
for(int i=1;i<=n;i++) jc[i]=(jc[i-1]*i)%mod; ll ans=0;
for(int i=2;i<=n;i++){
ans=(ans+cnt[i]*jc[n-i])%mod;
ans=(ans+mod-cnt[i]*i%mod*jc[n-i]%mod)%mod;
}
ans=(ans+cnt[1]*jc[n-1])%mod;
printf("%lld\n",ans);
return 0;
}