• 【BZOJ4361】isn 动态规划+树状数组+容斥


    【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

    题解:想到动归+树状数组+容斥,但是容斥系数想复杂了~

    我们希望先求出所有长度为i的非降序列个数,可以用DP解决。设f[i][j]表示最大值为i,长度为j的非降序列个数,用树状数组优化转移即可。

    然后用g[i]表示$sum f[..][j]$。因为其它数删除的顺序可以随便选,所以g[i]*=(n-i)!。但是有可能删到一半就已经得到了一个非降序列,怎么除去不合法状态呢?容斥呗!

    一开始想了半天容斥系数,但其实g[i]-=g[i+1]*(i+1)即可。因为删到一般就得到非降序列情况刚好是g[i+1]。

    时间复杂度$O(n^2log n)$

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int P=1000000007;
    int n,m;
    ll ans;
    int val[2010],v[2010],p[2010];
    int s[2010][2010];
    ll f[2010],c[2010][2010],jc[2010],jcc[2010],ine[2010];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    bool cmp(const int &a,const int &b)
    {
    	return val[a]<val[b];
    }
    inline void updata(int x,int y,int z)
    {
    	if(!z)	return ;
    	f[y]+=z;
    	for(int i=x;i<=m;i+=i&-i)
    	{
    		s[y][i]+=z;
    		if(s[y][i]>=P)	s[y][i]-=P;
    	}
    }
    inline int query(int x,int y)
    {
    	int i,ret=0;
    	for(i=x;i;i-=i&-i)
    	{
    		ret+=s[y][i];
    		if(ret>=P)	ret-=P;
    	}
    	return ret;
    }
    int main()
    {
    	n=rd();
    	int i,j;
    	jc[0]=jc[1]=jcc[0]=jcc[1]=ine[0]=ine[1]=1;
    	for(i=2;i<=n;i++)	jc[i]=jc[i-1]*i%P,ine[i]=P-(P/i)*ine[P%i]%P,jcc[i]=jcc[i-1]*ine[i]%P;
    	for(i=0;i<=n;i++)
    	{
    		c[i][0]=1;
    		for(j=1;j<=i;j++)	c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
    	}
    	for(i=1;i<=n;i++)	val[i]=rd(),p[i]=i;
    	sort(p+1,p+n+1,cmp);
    	for(i=1;i<=n;i++)
    	{
    		if(i==1||val[p[i]]>val[p[i-1]])	m++;
    		v[p[i]]=m;
    	}
    	for(i=1;i<=n;i++)
    	{
    		for(j=i;j>=2;j--)	updata(v[i],j,query(v[i],j-1));
    		updata(v[i],1,1);
    	}
    	for(i=1;i<=n;i++)	f[i]=f[i]%P*jc[n-i]%P;
    	for(i=1;i<=n;i++)	f[i]=(f[i]-f[i+1]*(i+1)%P+P)%P,ans=(ans+f[i])%P;
    	printf("%lld",ans);
    	return 0;
    }//4 1 2 3 4
  • 相关阅读:
    java常见异常总结
    敏捷开发的七种主流方法
    转:一位10年Java工作经验的架构师聊Java和工作经验
    Map遍历
    Mybatis中的模糊查询
    Mybatis中动态SQL多条件查询
    J2EE,LAMP和ASP.NET三者比较
    关于加密
    Md5Hash的测试
    CentOS7 修改默认时区为 北京时间
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8010979.html
Copyright © 2020-2023  润新知