1. 程式人生 > 實用技巧 >Luogu P6630 [ZJOI2020] 傳統藝能

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\)。滿足\(x\le L,R\le y<r\)(左兒子)或\(l<x\le L,R\le y\)(右兒子),此時有\(f_x'=g_x'=1\)
  3. \(x\)到根路徑上的點被標記。滿足\(x\le l,y\le r\),此時顯然\(f_x'=f_x,g_i'=1\)
  4. 其父親節點被修改且標記未下傳到\(x\)。滿足\(R<x\le r\)(左兒子)或\(l\le y<L\)(右兒子),此時有\(f_x'=g_x'=g_x\)
  5. 修改的點在\(x\)子樹內(不包括\(x\)
    ),滿足\(L<x\le y\le R\)\(L\le x\le y<R\),此時有\(f_x'=g_x'=0\)

第五類情況顯然不需要轉移,樸素的轉移是\(O(nk)\)的,單非常容易看出這題每個點其實是獨立的,因此可以矩陣乘法優化

我們設以上進行\(1,2,3,4\)四類轉移的概率分別是\(a,b,c,d\),顯然可以構造轉移矩陣:

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

總複雜度\(O(3^3\log k\times 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;
}