[BZOJ4361]isn(DP+容斥+树状数组)

先用树状数组求出g[i]表示长度为i的不降子序列个数。$O(n^2\log n)$

容斥,最终序列长度为i的方案数为g[i]*(n-i)!,但这里多计算了在删得只剩i个数之前就已经构成不降子序列的情况。

这时考虑最后是从哪个不降子序列删掉一个数的,g[i+1]*(n-i-1)!*(i+1),这里显然不会重复斥掉方案。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=2010,mod=1e9+7;
 9 int n,ans,a[N],b[N],fac[N],c[N][N],f[N][N],g[N];
10 void add(int c[],int x,int k){ for (; x<=n; x+=x&-x) c[x]=(c[x]+k)%mod; }
11 int que(int c[],int x){ int res=0; for (; x; x-=x&-x) res=(res+c[x])%mod; return res; }
12 
13 int main(){
14     freopen("bzoj4361.in","r",stdin);
15     freopen("bzoj4361.out","w",stdout);
16     scanf("%d",&n);
17     rep(i,1,n) scanf("%d",&a[i]),b[i]=a[i];
18     sort(b+1,b+n+1);
19     rep(i,1,n) a[i]=lower_bound(b+1,b+n+1,a[i])-b;
20     fac[1]=1; rep(i,2,n) fac[i]=1ll*fac[i-1]*i%mod;
21     add(c[0],1,1);
22     rep(i,1,n) for (int j=i; j; j--)
23         f[i][j]=(f[i][j]+que(c[j-1],a[i]))%mod,add(c[j],a[i],f[i][j]);
24     rep(i,1,n) rep(j,i,n) g[i]=(g[i]+f[j][i])%mod;
25     rep(i,1,n) ans=(ans+((1ll*fac[n-i]*g[i]%mod-1ll*fac[n-i-1]*g[i+1]%mod*(i+1)%mod)%mod+mod)%mod)%mod;
26     printf("%d\n",ans);
27     return 0;
28 }

 

posted @ 2018-11-05 11:04  HocRiser  阅读(224)  评论(0编辑  收藏  举报