bzoj 4361: isn 树状数组+动态规划

来源:互联网 发布:淘宝生意参谋 编辑:程序博客网 时间:2024/06/06 11:49

题意

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

分析

一眼看过去一点思路都没有,再多看几眼,还是没有思路。。。果然还是我太菜了

首先我们可以通过树状数组优化dp算出g[i]表示长度为i的不下降序列数量。
对于长度为i的不下降序列,单看其贡献的话就是g[i](ni)!,但会出现在操作完之前就结束的情况,因为所有不合法的情况一定是由长度为i+1的不下降序列转移过来的,所以就要减去g[i+1](ni1)!(i+1)。在减去的方案中,无论这是不是合法的方案,都会在之前就已经被计入ans中,所以这样做是对的。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=2005;const int MOD=1000000007;int n,a[N],w[N],c[N],f[N][N],jc[N],g[N];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void ins(int x,int y){    while (x<=n) c[x]+=y,c[x]-=c[x]>=MOD?MOD:0,x+=x&(-x);}int query(int x){    int ans=0;    while (x) ans+=c[x],ans-=ans>=MOD?MOD:0,x-=x&(-x);    return ans;}int main(){    n=read();    for (int i=1;i<=n;i++) a[i]=read(),w[i]=a[i];    sort(w+1,w+n+1);    int w1=unique(w+1,w+n+1)-w-1;    for (int i=1;i<=n;i++) a[i]=lower_bound(w+1,w+w1+1,a[i])-w;    for (int i=1;i<=n;i++) f[i][1]=1;    for (int j=2;j<=n;j++)    {        for (int i=1;i<=n;i++) c[i]=0;        for (int i=j-1;i<=n;i++) f[i][j]=query(a[i]),ins(a[i],f[i][j-1]);    }    for (int i=1;i<=n;i++)        for (int j=1;j<=n;j++)            g[i]+=f[j][i],g[i]-=g[i]>=MOD?MOD:0;    jc[0]=1;    for (int i=1;i<=n;i++) jc[i]=(LL)jc[i-1]*i%MOD;    LL ans=0;    for (int i=1;i<n;i++) (ans+=(LL)g[i]*jc[n-i]-(LL)g[i+1]*jc[n-i-1]%MOD*(i+1))%=MOD;    ans+=g[n];ans-=ans>=MOD?MOD:0;ans+=ans<0?MOD:0;    printf("%lld",ans);    return 0;}
阅读全文
0 0
原创粉丝点击