bzoj4361 isn

Description

给出一个长度为n的序列A(A1,A2...AN)。如果序列A不是非降的,你必须从中删去一个数,
这一操作,直到A非降为止。求有多少种不同的操作方案,答案模10^9+7。

Input

第一行一个整数n。
接下来一行n个整数,描述A。

Output

一行一个整数,描述答案。

Sample Input

4
1 7 5 3

Sample Output

18

HINT

1<=N<=2000

 

正解:$dp$+树状数组。

感觉自己有点智商掉线,挺简单的一道题竟然没想出来。。

首先我们把所有方案数按照最后剩下的序列长度分类。

那么$ans=\sum_{i=1}^{n}f[i]*(n-i)!$,其中$f[i]$为长度为$i$的不降序列个数。

我们发现这样会算重,然后可以注意到算重的充要条件就是当这个序列的长度为$i+1$时就已经不降了。

所以再减去$f[i+1]*(i+1)*(n-i-1)!$即可。求$f$用一个简单的树状数组优化$dp$就行了。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define rhl (1000000007)
 6 #define lb(x) (x & -x)
 7 #define N (2005)
 8 
 9 using namespace std;
10 
11 int c[N][N],a[N],f[N],fac[N],hsh[N],n,tot,ans;
12 
13 il int gi(){
14   RG int x=0,q=1; RG char ch=getchar();
15   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
16   if (ch=='-') q=-1,ch=getchar();
17   while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
18   return q*x;
19 }
20 
21 il void add(RG int op,RG int x,RG int v){
22   for (;x<=tot;x+=lb(x)){
23     c[op][x]+=v; if (c[op][x]>=rhl) c[op][x]-=rhl;
24   }
25   return;
26 }
27 
28 il int query(RG int op,RG int x){
29   RG int res=0;
30   for (;x;x^=lb(x)){
31     res+=c[op][x]; if (res>=rhl) res-=rhl;
32   }
33   return res;
34 }
35 
36 int main(){
37 #ifndef ONLINE_JUDGE
38   freopen("isn.in","r",stdin);
39   freopen("isn.out","w",stdout);
40 #endif
41   n=gi(),fac[0]=1;
42   for (RG int i=1;i<=n;++i)
43     hsh[i]=a[i]=gi(),fac[i]=1LL*fac[i-1]*i%rhl;
44   sort(hsh+1,hsh+n+1),tot=unique(hsh+1,hsh+n+1)-hsh-1;
45   for (RG int i=1;i<=n;++i){
46     a[i]=lower_bound(hsh+1,hsh+tot+1,a[i])-hsh;
47     for (RG int j=i,tmp;j;--j){
48       tmp=j==1?1:query(j-1,a[i]),add(j,a[i],tmp);
49       f[j]+=tmp; if (f[j]>=rhl) f[j]-=rhl;
50     }
51   }
52   for (RG int i=1;i<=n;++i){
53     ans=(1LL*fac[n-i]*f[i]+ans)%rhl;
54     if (i<n) ans=(ans-1LL*fac[n-i-1]*f[i+1]%rhl*(i+1))%rhl;
55   }
56   cout<<(ans+rhl)%rhl; return 0;
57 }

 

posted @ 2018-02-27 08:50  wfj_2048  阅读(171)  评论(0编辑  收藏  举报