zoukankan      html  css  js  c++  java
  • bzoj4361-isn

    题意

    给出一个数列(a),当这个数列不是不下降的时候我们删除其中一个数,直到它是不下降的。

    问有多少种删除方案。(nle 2000)

    分析

    直接算方案数比较难办,转而计算序列数。

    如果不考虑不合法的删除(变成不下降之后继续删),那么设长度为(i)的不下降子序列有(g_i)个,那么得到长度为(i)的子序列的方案数为(g_i(n-i)!)

    现在我们求出所有不管不合法的(g_i),那么(g_i)中的不合法情况必定是从(g_{i+1})删除一个位置得到的,这是因为(g_{i+1})包含了(g_i)的直接不合法情况和间接不合法情况,因为它自己包含了后面的不合法情况。例子(a=(1,7,3,5))可以清楚地说明这一点。

    [ans=sum g_i(n-i)!-g_{i+1}(n-i-1)!(i+1) ]

    (g_i)如何求呢?退而求其次,我们算(f[i][j]),表示长度为(i)(j)结尾的子序列数量。

    [egin{aligned} f[i][j]=sum f[i-1][k] && k<j,a_kle a_j end{aligned} ]

    离散化(a),用树状数组可以优化到(O(n^2log n))

    这题关键是首先要想到求序列数,接着就是通过减掉不合法情况来计算。

    代码

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<numeric>
    #include<algorithm>
    using namespace std;
    typedef long long giant;
    int read() {
    	int x=0,f=1;
    	char c=getchar();
    	for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    	for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*f;
    }
    const int maxn=2e3+1;
    const int q=1e9+7;
    inline int Plus(int x,int y) {return ((giant)x+(giant)y)%q;}
    inline int Multi(int x,int y) {return (giant)x*y%q;}
    inline int Sub(int x,int y) {return Plus(x,q-y);}
    int a[maxn],b[maxn],c[maxn],fac[maxn],n,f[maxn][maxn],g[maxn];
    inline int lowbit(int x) {return x&-x;}
    inline void inc(int x,int d) {for (;x<=n;x+=lowbit(x)) c[x]=Plus(c[x],d);}
    inline int sum(int x) {
    	int ret=0;
    	for (;x;x-=lowbit(x)) ret=Plus(ret,c[x]);
    	return ret;
    }
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    #endif
    	n=read();
    	fac[0]=1;
    	for (int i=1;i<=n;++i) fac[i]=Multi(fac[i-1],i);
    	for (int i=1;i<=n;++i) a[i]=b[i]=read();
    	sort(b+1,b+n+1);
    	int m=unique(b+1,b+n+1)-b-1;
    	for (int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+m+1,a[i])-b;
    	for (int i=1;i<=n;++i) f[1][i]=1;
    	for (int i=2;i<=n;++i) {
    		memset(c,0,sizeof c);
    		for (int j=1;j<=n;++j) {
    			f[i][j]=Plus(f[i][j],sum(a[j]));
    			inc(a[j],f[i-1][j]);
    		}
    	}
    	for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) g[i]=Plus(g[i],f[i][j]);
    	int ans=0;
    	for (int i=n;i;--i) ans=Plus(ans,Sub(Multi(g[i],fac[n-i]),Multi(Multi(g[i+1],fac[n-i-1]),i+1)));
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    外部无法捕捉Realm的doGetAuthenticationInfo方法抛出的异常
    Redis多实例及主从搭建
    Redis安装
    window.showModalDialog两次加载问题清除缓存方法
    JQuery分页插件bs_pagination的应用
    解决IE11出现异常SCRIPT5011:不能执行已释放Script的代码
    通过CSS禁用页面模块的复制和粘贴功能
    C# toString()转换详细(转)
    百度ue富文本编辑器setContent方法报错初始化加载内容失败解决办法
    前端页面div float 后高度 height 自适应的问题
  • 原文地址:https://www.cnblogs.com/owenyu/p/7151064.html
Copyright © 2011-2022 走看看