zoukankan      html  css  js  c++  java
  • Luogu P6630 [ZJOI2020] 传统艺能

    这题真是ZJOI的签到题,考场上想都没想真是太屑了的说

    考虑利用[ZJOI2019]线段树教给我们的DP方法,设(f_{i,j})表示(i)轮后(j)点标记为(1)的概率,(g_{i,j})表示(i)轮后(j)点到根的路径上任意一点标记为(1)的概率

    我们考虑(f_{i-1,x},g_{i-1,x})(以下简称(f_x,g_x))如何转移到(f_{i,x},g_{i,x})(以下简称(f_x',g_x')

    假设节点(x)的区间为([L,R]),其父节点的区间为([l,r]),修改的区间为([x,y]),考虑以下的五种转移:

    1. 修改的区间与其父节点不交。满足(y<l)(x>r),此时显然(f_x'=f_x,g_x'=g_x)
    2. 其父亲节点被修改且标记下传到(x)。满足(xle L,Rle y<r)(左儿子)或(l<xle L,Rle y)(右儿子),此时有(f_x'=g_x'=1)
    3. (x)到根路径上的点被标记。满足(xle l,yle r),此时显然(f_x'=f_x,g_i'=1)
    4. 其父亲节点被修改且标记未下传到(x)。满足(R<xle r)(左儿子)或(lle y<L)(右儿子),此时有(f_x'=g_x'=g_x)
    5. 修改的点在(x)子树内(不包括(x)),满足(L<xle yle R)(Lle xle y<R),此时有(f_x'=g_x'=0)

    第五类情况显然不需要转移,朴素的转移是(O(nk))的,单非常容易看出这题每个点其实是独立的,因此可以矩阵乘法优化

    我们设以上进行(1,2,3,4)四类转移的概率分别是(a,b,c,d),显然可以构造转移矩阵:

    [egin{bmatrix} a+c,d,b\ 0,a+d,b+c\ 0,0,1 end{bmatrix} imes egin{bmatrix} f_x\ g_x\ 1 end{bmatrix} = egin{bmatrix} f_x'\ g_x'\ 1 end{bmatrix} ]

    总复杂度(O(3^3log k imes n))

    #include<cstdio>
    #include<cstring>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=200005,mod=998244353;
    struct Matrix
    {
    	int n,m; long long mat[3][3];
    	inline Matrix(CI N=0,CI M=0)
    	{
    		n=N; m=M; memset(mat,0,sizeof(mat));
    	}
    	inline long long* operator [] (CI x) { return mat[x]; }
    	friend inline Matrix operator * (Matrix A,Matrix B)
    	{
    		Matrix C(A.n,B.m); RI i,j,k; for (i=0;i<C.n;++i)
    		for (j=0;j<C.m;++j) for (k=0;k<A.m;++k)
    		C[i][j]+=1LL*A[i][k]*B[k][j];
    		for (i=0;i<C.n;++i) for (j=0;j<C.m;++j) C[i][j]%=mod; return C;
    	}
    	friend inline Matrix operator ^ (Matrix A,int p)
    	{
    		Matrix T(A.n,A.m); for (RI i=0;i<T.n;++i) T[i][i]=1;
    		for (;p;p>>=1,A=A*A) if (p&1) T=T*A; return T;
    	}
    };
    int n,k,ans,div;
    inline int C2(CI x)
    {
    	if (!x) return 0; return (1LL*x*(x+1)>>1LL)%mod;
    }
    inline int sum(CI x,CI y)
    {
    	int t=x+y; return t>=mod?t-mod:t;
    }
    inline int quick_pow(int x,int p=mod-2,int mul=1)
    {
    	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
    }
    inline void DFS(CI L=1,CI R=n,CI l=0,CI r=0) //[L,R] self interval; [l,r] father's interval
    {
    	if (L<R) { int x; scanf("%d",&x); DFS(L,x,L,R); DFS(x+1,R,L,R); }
    	if (!l) return (void)(ans=sum(ans,div)); int a,b,c,d;
    	a=1LL*sum(C2(l-1),C2(n-r))*div%mod; b=1LL*sum(1LL*L*(r-R)%mod,1LL*(n-R+1)*(L-l)%mod)*div%mod;
    	c=1LL*l*(n-r+1)%mod*div%mod; d=(1LL*(r-R)*(2*n-r-R+1)+1LL*(L-l)*(l+L-1)>>1LL)%mod*div%mod;
    	Matrix P(3,3); P[0][0]=sum(a,c); P[0][1]=d; P[0][2]=b; P[1][1]=sum(a,d); P[1][2]=sum(b,c); P[2][2]=1;
    	P=P^k; ans=sum(ans,P[0][2]);
    }
    int main()
    {
    	return scanf("%d%d",&n,&k),div=quick_pow(C2(n)),DFS(),printf("%d",ans),0;
    }
    
  • 相关阅读:
    Python 魔术方法
    Python 类和对象-上
    Python 日期时间相关
    Python OS模块
    Python文件操作
    Python集合操作
    Python字典操作
    为什么最小帧长度是64字节
    字典_ 三级菜单
    cart_购物车小程序
  • 原文地址:https://www.cnblogs.com/cjjsb/p/13396786.html
Copyright © 2011-2022 走看看