• bzoj 4361: isn


    4361: isn

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 539  Solved: 269
    [Submit][Status][Discuss]

    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
    设 g[i][j] 为以第i位结尾,且目前非降子序列长度为j 的方案数。
    显然 :
          1.g[i][1] = 1;
          2.g[i][j] = Σg[k][j-1]  ,其中 1<=k<i 且  a[k]<=a[i]。
    然后这个玩意可以用树状数组优化,处理一下前缀就行了。
     
    那么答案就是Σg[][i] * (n-i)! - g[][i+1] * (n-i-1)! * (i+1)。
    为什么呢?
    因为我们要减去不合法的方案,而最后删到剩k位的方案有g[][k] * (n-k)! 种,
    但是其中有 g[][k+1] * (n-k-1)! * (k+1) 种是不合法的,因为合法的方案是删到剩k+1位时候还不是非降序列。
     
    /*
        g[i][j]表示到第i为,上升长度为j的方案数  
        ans= g[i]*(n-i)! - g[i+1]*(n-i-1)!*(i+1)
    */
    #include<bits/stdc++.h>
    #define ll long long
    #define maxn 2005
    using namespace std;
    const int ha=1000000007;
    int num[maxn],ky;
    int f[maxn][maxn],n,m;
    int a[maxn],g[maxn][maxn],ans;
    
    inline int add(int x,int y){
    	x+=y;
    	return x>=ha?x-ha:x;
    }
    
    inline void update(int lev,int x,int y){
    	for(;x<=ky;x+=x&-x) f[lev][x]=add(f[lev][x],y);
    }
    
    inline int query(int lev,int x){
    	int an=0;
    	for(;x;x-=x&-x) an=add(an,f[lev][x]);
    	return an;
    }
    
    inline void dp(){
    	for(int i=1;i<=n;i++)
    	    for(int j=i;j;j--){
    	    	if(j>1) g[i][j]=query(j-1,a[i]);
    	    	else g[i][j]=1;
    	    	update(j,a[i],g[i][j]);
    		} 
    	
    	for(int i=1;i<=n;i++)
    	    for(int j=1;j<=n;j++) g[0][j]=add(g[0][j],g[i][j]);
    }
    
    inline void calc(){
    	int tmp=1,pre=1;
    	for(int i=n;i;i--,pre=tmp,tmp=tmp*(ll)(n-i)%ha){
    		ans=add(ans,add(g[0][i]*(ll)tmp%ha,ha-g[0][i+1]*(ll)pre%ha*(ll)(i+1)%ha));
    	}
    }
    
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",a+i),num[i]=a[i];
    	sort(num+1,num+n+1);
    	ky=unique(num+1,num+n+1)-num-1;
    	for(int i=1;i<=n;i++) a[i]=lower_bound(num+1,num+ky+1,a[i])-num;
    	dp();
    	calc();
    	cout<<ans<<endl;
    	return 0;
    }
    

      

  • 相关阅读:
    css--一些基本属性
    python网络编程--TCP连接的三次握手(三报文握手)与四次挥手
    python--基础数据类型 set集合
    图片
    python--变量,常量,用户交互
    前端基础--css基本语法,选择器
    Python----一些面试题
    HTML--基本标签
    集合类型
    字典类型
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8574756.html
Copyright © 2020-2023  润新知