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
$f[i][j]$表示前i个数,不下降序列长为j的方案数
$F[j]=\sum_{i=1}^{n}f[i][j]$即不下降序列长为j的总方案数
但是会有重复,假设在长度为j+1时就已经构成了,那么长度为j的F[j]就会重复计算一部分
所以长度为i的方案:
$ans[i]=F[i]*fac[n-i]-F[i+1]*(i+1)*fac[n-i-1]$
这样DP要$O(n^3)$
用离散+树状数组(线段树)优化,复杂度$O(n^2logn)$
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long lol;
 8 int Mod=1e9+7,n,a[2005],b[2005],m;
 9 int c[2005][2005],fac[2005],tmp,F[2005],ans;
10 void update(int x,int p,int k)
11 {
12   while (x<=n)
13     {
14       c[p][x]+=k;
15       if (c[p][x]>=Mod) c[p][x]-=Mod;
16       x+=(x&(-x));
17     }
18 }
19 int query(int x,int p)
20 {
21   int s=0;
22   while (x)
23     {
24       s+=c[p][x];
25       if (s>=Mod) s-=Mod;
26       x-=(x&(-x));
27     }
28   return s;
29 }
30 int main()
31 {int i,j;
32   cin>>n;
33   fac[0]=1;
34   for (i=1;i<=n;i++)
35     fac[i]=1ll*fac[i-1]*i%Mod;
36   for (i=1;i<=n;i++)
37     {
38       scanf("%d",&a[i]);
39       b[i]=a[i];
40     }
41   sort(b+1,b+n+1);
42   m=unique(b+1,b+n+1)-b-1;
43   for (i=1;i<=n;i++)
44     a[i]=lower_bound(b+1,b+m+1,a[i])-b;
45   for (i=1;i<=n;i++)
46     {
47       for (j=i;j>=1;j--)
48     {
49       if (j==1) tmp=1;
50       else tmp=query(a[i],j-1);
51       update(a[i],j,tmp);
52       F[j]+=tmp;
53       if (F[j]>=Mod) F[j]-=Mod;
54     }
55     }
56   for (i=1;i<=n;i++)
57     {
58       ans+=1ll*F[i]*fac[n-i]%Mod;
59       if (ans>=Mod) ans-=Mod;
60       if (i<n)
61     ans=(ans-1ll*F[i+1]*fac[n-i-1]%Mod*(i+1)%Mod+Mod)%Mod;
62     }
63   cout<<ans;
64 }

 

posted @ 2018-03-04 19:22  Z-Y-Y-S  阅读(200)  评论(0编辑  收藏  举报