zoukankan      html  css  js  c++  java
  • ●BZOJ 4361 isn

    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=4361

    题解:

    容斥,DP,树状数组
    注意题意:一旦变成了非降序列,就停止操作。即对非降序列进行操作是非法的。
    首先求出 dp[i][j]:表示以第i个数作为结尾且长度为j的不降序列的种类数
    转移显然 : dp[i][j]+=dp[k][j-1] k<i且a[k]<=a[j],复杂度 O(N^3)
    可以用 树状数组优化到 O(N^2*log2N),(要开 N个树状数组)
    然后得到 g[j]+=dp[i][j]:表示长度为 j的不降序列的种类数。
    在令 w[i]=g[i]*(N-i)!含义是留下的i个数,组成非降序列,那 N-i个数有(N-i)!种方法把它们拿走。
    那么 答案就是  w[1] + w[2] + w[3] +.....
    完了么?当然没有,细细一想,w[ ]好像有问题:
    不是说一旦变成了非降序列,就要停止操作么,
    所以 w[i]完全可能会存在某个方案还没操作完就已经非降了,那么要减去这些方案。
    怎么减呢?
    不难发现,w[i+1]里包含了两类方案,
    一类是取了N-(i+1)个数后恰好变成非降序列,这类是合法的操作
    另一类是还没有取到第N-(i+1)个数就已经非降了,那么这类操作就是非法的
    同时对于 w[i]来说,其中包含的非法方案就是上面两类操作的方案数*(i+1),                  
    即w[i+1]*(i+1)
    所以减去就好了 : w[i]-=w[i+1]*(i+1)
    最后的答案才是 w[1] + w[2] + w[3] +.....

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 2050
    #define _ %mod
    #define filein(x) freopen(#x".in","r",stdin);
    #define fileout(x) freopen(#x".out","w",stdout);
    using namespace std;
    const int mod=1000000007;
    struct BIT{
    	int val[MAXN][MAXN],N;
    	void Init(int n){
    		N=n; 
    		memset(val,0,sizeof(val));
    	}
    	int Lowbit(int x){
    		return x&-x;
    	}
    	void Modify(int id,int p,int x){
    		for(int i=p;i<=N;i+=Lowbit(i))
    			val[id][i]=(1ll*val[id][i]+x)_;
    	}
    	int Query(int id,int p){
    		int ans=0;
    		for(int i=p;i;i-=Lowbit(i))
    			ans=(1ll*ans+val[id][i])_;
    		return ans;
    	}
    }t;
    int dp[MAXN][MAXN],g[MAXN],a[MAXN],fac[MAXN]; //dp[i][j] 以i结尾,序列长度为 j的方案
    int N,ANS;
    int main()
    {
    	static int tmp[MAXN],M;
    	scanf("%d",&N); t.Init(N); fac[0]=1;
    	for(int i=1;i<=N;i++) fac[i]=(1ll*fac[i-1]*i)_;
    	for(int i=1;i<=N;i++) scanf("%d",&a[i]),tmp[i]=a[i];
    	sort(tmp+1,tmp+N+1); M=unique(tmp+1,tmp+N+1)-tmp-1;
    	for(int i=1;i<=N;i++) a[i]=lower_bound(tmp+1,tmp+M+1,a[i])-tmp;
    	for(int i=1;i<=N;i++){
    		for(int j=i;j>=2;j--){ 
    			dp[i][j]=t.Query(j-1,a[i]);
    			t.Modify(j,a[i],dp[i][j]);
    		}
    		dp[i][1]=1; t.Modify(1,a[i],dp[i][1]);
    	}
    	for(int j=1;j<=N;j++){ 
    		for(int i=1;i<=N;i++)
    			g[j]=(1ll*g[j]+dp[i][j])_;
    		g[j]=(1ll*g[j]*fac[N-j])_;
    	} 
    	for(int i=1;i<=N;i++)
    		g[i]=(1ll*g[i]-(1ll*g[i+1]*(i+1))_+mod)_,ANS=(1ll*ANS+g[i])_;
    	printf("%d",ANS);
    	return 0;
    }
    

  • 相关阅读:
    React 不暴露webpack配置的情况下,修改webpack配置
    Array的一些方法
    ES 6 学习
    位运算解决“一个数组中,只有一个数字出现n次,其他数字出现k次”问题
    句子反转——牛客刷题(java)
    数串——牛客刷题
    链表分割——牛客剑指offer
    合并两个排序链表——牛客offer
    复杂链表的复制——牛客offer
    两个链表的第一个公共结点——牛客offer
  • 原文地址:https://www.cnblogs.com/zj75211/p/8029380.html
Copyright © 2011-2022 走看看