【BZOJ 4361】 4361: isn (DP+树状数组+容斥)

4361: isn

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 218  Solved: 126

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

Source

 

 

【分析】

  考虑倒着想。

  你倒数第一步做之前还不是非降,做完之后就非降了,说明如果有一个上升序列,你加倒数第一个点时候不是上升序列了,前面的操作就可以任意了。

  本来想保证这个的,但是发现放入DP里还有一个关于长度的阶乘,根本不行。

  然后考虑容斥。

  现在的问题是:倒数第一个点x,放入序列里面还是非降的,这个时候不应该计算。

  即操作结束在更之前。把这些不合法的减掉就好了。

  g[i]表示长度为i的上升序列个数

  那么贡献就是$g[i]*(n-i)!-g[i+1]*(i+1)*(n-i-1)!$

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 2010
 8 #define Mod 1000000007
 9 // #define LL long long
10 
11 int f[Maxn][Maxn],g[Maxn],fac[Maxn],c[Maxn],a[Maxn];
12 
13 struct node {int x,id;}t[Maxn];
14 bool cmp(node x,node y) {return x.x<y.x;}
15 
16 int mx;
17 void add(int x,int y)
18 {
19     for(int i=x;i<=mx;i+=i&(-i))
20     {
21         c[i]=(c[i]+y)%Mod;
22     }
23 }
24 
25 int get_sum(int x)
26 {
27     int ans=0;
28     for(int i=x;i>=1;i-=i&(-i))
29      ans=(ans+c[i])%Mod;
30     return ans;
31 }
32 
33 int main()
34 {
35     int n;
36     scanf("%d",&n);
37     for(int i=1;i<=n;i++)
38     {
39         int x;scanf("%d",&x);
40         t[i].x=x;t[i].id=i;
41     }
42     sort(t+1,t+1+n,cmp);
43     mx=1;a[t[1].id]=1;
44     for(int i=2;i<=n;i++)
45     {
46         if(t[i].x!=t[i-1].x) mx++;
47         a[t[i].id]=mx;
48     }
49     for(int i=1;i<=n;i++) f[1][i]=1;
50     for(int i=2;i<=n;i++)
51     {
52         for(int j=0;j<=n;j++) c[j]=0;
53         for(int j=1;j<=n;j++)
54         {
55             f[i][j]=get_sum(a[j]);
56             add(a[j],f[i-1][j]);
57         }
58     }
59     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) g[i]=(g[i]+f[i][j])%Mod;
60     fac[0]=1;for(int i=1;i<=n;i++) fac[i]=1LL*fac[i-1]*i%Mod;
61     int ans=0;
62     ans=(ans+g[n]);
63     for(int i=1;i<n;i++)
64     {
65         ans=(ans+1LL*g[i]*fac[n-i]%Mod-1LL*fac[n-i-1]*g[i+1]%Mod*(i+1)%Mod)%Mod;
66     }
67     ans=(ans+Mod)%Mod;
68     printf("%d\n",ans);
69     return 0;
70 }
View Code

 

2017-04-20 17:01:57

posted @ 2017-04-20 17:01  konjak魔芋  阅读(226)  评论(0编辑  收藏  举报