zoukankan      html  css  js  c++  java
  • UOJ#196. 【ZJOI2016】线段树 概率期望,动态规划

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ196.html

    题解

    先离散化,设离散化后的值域为 $[0,m]$ 。

    首先把问题转化一下,变成:对于每一个位置 $i$ ,求出它最终不超过 $j$ 的方案数。

    考虑如何求这个东西。

    对于一个固定的 $j$ ,考虑一个这样的过程:

    初始时,有若干个区间,两两不相交,且区间内的元素都小于等于 $j$ ,而且每一个区间都不能在满足条件的基础上,向左右任意一侧扩张。

    考虑其中的一个区间 $[L,R]$ ,如果出现了操作使得它的边界变成了比 $j$ 大的值,那么这个区间会缩小。

    考虑对于他的所有子区间 $[x,y]$ ,求出 $q$ 次操作之后, $[L,R]$ 缩小成 $[x,y]$ 的方案数。

    这东西显然可以列出 DP 方程:设 $dp[x][i][j]$ 表示当前进行了 $x$ 次操作,初始区间变成 $[i,j]$ 方案数,则:

    $$egin{eqnarray*}dp[x][i][j]&=&left (frac{(i-1)i}2 + frac{(j-i+1)(j-i+2)}2 + frac {(n-j)(n-j+1)}2 ight )dp[x-1][i][j] \ &+& sum_{k=L}^{i-1} dp[x-1][k][j] cdot (k-1) \ &+& sum_{k=j+1}^R  dp[x-1][i][k] cdot (n-k) end{eqnarray*}$$

    这样的话看上去总的运算量是 $O(n^4)$ 的。

    考虑到题目中保证数据随机。

    那么,如果对序列建一棵笛卡尔树,那么这个笛卡尔树是基本平衡的,可以近似看做一棵满二叉树。

    而我们要求的区间只有 $O(n)$ 个,是对于每一个位置 $i$ ,到它两侧第一个比他大的数之前,这个范围内的区间答案。

    这个东西放在笛卡尔树上就是子树的size,而对一个区间进行dp的复杂度是 $O(qcdot size^2)$ ,又由于这棵笛卡尔树可以近似看做满二叉树,所以求个和就可以发现复杂度总和是 $O(n^2q)$ 的,可以通过此题。

    代码

    #pragma GCC optimize("Ofast","inline")
    #include <bits/stdc++.h>
    #define clr(x) memset(x,0,sizeof (x))
    #define For(i,a,b) for (int i=a;i<=b;i++)
    #define Fod(i,b,a) for (int i=b;i>=a;i--)
    #define pb(x) push_back(x)
    #define mp(x,y) make_pair(x,y)
    #define fi first
    #define se second
    #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
    #define outval(x) printf(#x" = %d
    ",x)
    #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
    #define outtag(x) puts("----------"#x"----------")
    #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);
    					    For(_v2,L,R)printf("%d ",a[_v2]);puts("");
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector <int> vi;
    LL read(){
    	LL x=0,f=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		f|=ch=='-',ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return f?-x:x;
    }
    const int N=405,mod=1e9+7,INF=mod;
    void Add(int &x,int y){
    	if ((x+=y)>=mod)
    		x-=mod;
    }
    void Del(int &x,int y){
    	if ((x-=y)<0)
    		x+=mod;
    }
    int Pow(int x,int y){
    	int ans=1;
    	for (;y;y>>=1,x=(LL)x*x%mod)
    		if (y&1)
    			ans=(LL)ans*x%mod;
    	return ans;
    }
    int n,q;
    int a[N];
    int val[N][N];
    vector <int> Ha;
    int tmp[N][N];
    int dp[2][N][N];
    void solve(int L,int R,int t){
    	For(i,L,R)
    		For(j,i,R)
    			dp[0][i][j]=0;
    	dp[0][L][R]=1;
    	For(c,1,q){
    		int _0=(c^1)&1,_1=c&1;
    		For(i,L,R)
    			For(j,i,R)
    				dp[_1][i][j]=(LL)tmp[i][j]*dp[_0][i][j]%mod;
    		For(j,L,R){
    			int s=0;
    			For(i,L,j){
    				Add(dp[_1][i][j],s);
    				Add(s,(LL)dp[_0][i][j]*(i-1)%mod);
    			}
    		}
    		For(i,L,R){
    			int s=0;
    			Fod(j,R,i){
    				Add(dp[_1][i][j],s);
    				Add(s,(LL)dp[_0][i][j]*(n-j)%mod);
    			}
    		}
    	}
    	For(j,L,R){
    		int s=0;
    		For(i,L,j){
    			Add(s,dp[q&1][i][j]);
    			Add(val[i][t],s);
    		}
    	}
    }
    int main(){
    	n=read(),q=read();
    	For(i,1,n)
    		a[i]=read(),Ha.pb(a[i]);
    	sort(Ha.begin(),Ha.end());
    	Ha.erase(unique(Ha.begin(),Ha.end()),Ha.end());
    	For(i,1,n)
    		a[i]=lower_bound(Ha.begin(),Ha.end(),a[i])-Ha.begin();
    	For(i,1,n)
    		For(j,1,n)
    			tmp[i][j]=(i-1)*i/2+(j-i+1)*(j-i+2)/2+(n-j)*(n-j+1)/2;
    	a[0]=a[n+1]=Ha.size();
    	For(t,0,(int)Ha.size()-1){
    		int L=0,Mx=0;
    		For(R,1,n+1)
    			if (a[R]<=t)
    				Mx=max(Mx,a[R]);
    			else {
    				if (L+1<=R-1){
    					if (Mx<t){
    						For(i,L+1,R-1)
    							Add(val[i][t],val[i][t-1]);
    					}
    					else
    						solve(L+1,R-1,t);
    				}
    				L=R,Mx=0;
    			}
    	}
    	For(i,1,n){
    		int ans=0;
    		Fod(j,(int)Ha.size()-1,1)
    			Del(val[i][j],val[i][j-1]);
    		For(j,0,(int)Ha.size()-1)
    			Add(ans,(LL)val[i][j]*Ha[j]%mod);
    		printf("%d ",ans);
    	}
    	puts("");
    	return 0;
    }
    

      

  • 相关阅读:
    nginx配置跨域问题
    几个经典的TCP通信函数
    表达格式和数值格式的转换
    主机字节序与网络字节序的转换
    一对经典的时间获取客户/服务器程序
    关于TIME_WAIT状态
    一个经典的比喻( 关于TCP连接API )
    《UNIX 网络编程 第二版》编译环境的搭建( 运行本专栏代码必读 )
    简述C++中的多态机制
    最佳谓词函数 --- 函数对象
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ196.html
Copyright © 2011-2022 走看看