其他分享
首页 > 其他分享> > [CEOI2020] D1T3 星际迷航 题解

[CEOI2020] D1T3 星际迷航 题解

作者:互联网

我的CEOI作战记录&题解-洛谷博客

我的CEOI作战记录&题解-cnblogs

首先思考 \(D=1\) 怎么做.

不难发现,如果一个时空隧道指向了一个必胜点,那么这个时空隧道相当于不存在;否则相当于强制把这一层的某个点 \(x\) 变为了必胜点.

换根 DP 求出 \(cnt_x\) 表示能使 \(x\) 胜负状态改变的强制把这一层的某个点 \(y\) 变为了必胜点的操作种数.

原树上的必胜点数目为 \(cntw\) ,必败点数目为 \(cntl\) ,记 \(win_x\) 表示原树上 \(x\) 是否必胜,是则为 \(1\) ,否则为 \(0\) .

那么对于 \(D=1\) ,答案就是 \(cnt_1 \times cntl + win_1 \times n \times cntw\) .

记 \(fw_i\) 为 把 \(i\) 强制变为必胜点之后的必胜点数目,特别的,令 \(fw_0=cntw\) . 记 \(sumcntw\) 为 \(\sum\limits_{i=1}^n fw_i\)

记 \(fl_i\) 为 把\(i\)强制变为必胜点之后的必败点数目\(,\)特别的\(,\)令 \(fl_0=cntl\) . 记 \(sumcntl\) 为 \(\sum\limits_{i=1}^n fl_i\)

对于 \(D>1\) 的情况\(,\)首先我们考虑 \(dp_{i,x(1\leq x\leq n)}\) 表示第\(i\)层的时空隧道连接了下一层的必败点\(,\)并使得\(x\)强制变为必胜点的方案数.

再记一个 \(dp_{i,0}\) 表示示第 \(i\) 层的时空隧道连接了下一层的必胜点的方案数.

如果我们能计算出这些东西\(,\)那么答案就是 \(\sum\limits_{i=0}^n dp_{1,i} \times (cnt_1 \times fl_i+win_1\times n \times fw_i)\)

那么怎么 DP 呢?

\(dp_{i,x(x>0)} = \sum\limits_{y=0}^n dp_{i+1,y} \times fl_y\)

\(dp_{i,0}=\sum\limits_{y=0}^n dp_{i+1,y} \times fw_y\)

不难发现所有的 \(dp_{i,1},dp_{i,2},...,dp_{i,n}\) 都相等,所以对于每个 \(i\) 我们只需要记两个 DP 值.

并且转移可以写成矩阵形式,而且无论是转移还是计算答案我们都不需要求出 \(fl_i\) 和 \(fw_i\) ,只需要求出它们的和 \(sumcntw\) , \(sumcntl\) . 这两个数可以通过上述的换根 DP 结果求出.

复杂度 \(O(n+\log D)\) 或 \(O(n\log n+\log D)\) 细节非常多.

\(O(n\log n+\log D)\) 代码 :

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int P = 1e9 + 7,N = 100050;
int n,ans,fa[N]; LL d; vector<int>G[N]; map<int,int>M[N];
inline void dfs1(int x,int f){
	fa[x] = f; for (int i = 0; i < G[x].size(); ++i) if (G[x][i] != fa[x]) dfs1(G[x][i],x);
}
int f1[N],f2[N];
inline void dp11(int x){
	f1[x] = 0;
	for (int i = 0; i < G[x].size(); ++i) if (G[x][i] ^ fa[x]){ dp11(G[x][i]); if (!f1[G[x][i]]) ++f1[x]; }
	M[x][fa[x]] = f1[x];
}
inline void dp22(int x){
	int y; if (y = fa[x]) f2[x] = f1[y] - (f1[x] ? 0 : 1) + ((fa[y] && !f2[y]) ? 1 : 0);
	M[fa[x]][x] = f2[x]; for (int i = 0; i < G[x].size(); ++i) if (G[x][i] != fa[x]) dp22(G[x][i]);
}
inline int DP(int x,int y){
	if (M[x].count(y)) return M[x][y]; int cnt = 0;
	for (int i = 0; i < G[x].size() && cnt <= 1; ++i) if (G[x][i] != y && !DP(G[x][i],x)) ++cnt;
	return M[x][y] = cnt;
}
int dp0[N],dp1[N],win[N];
inline void dfs(int x,int f){
	fa[x] = f;
	if (x == 1){ dp0[x] = 0,dp1[x] = 1; for (int i = 0; i < G[1].size(); ++i) dfs(G[1][i],1); return; }
	int numf = DP(fa[x],fa[fa[x]]);
	if (numf > 1) dp0[x] = dp1[x] = dp1[fa[x]];
	else if (numf == 1){ if (!DP(x,fa[x])) dp0[x] = dp1[fa[x]],dp1[x] = dp0[fa[x]]; else dp0[x] = dp1[x] = dp1[fa[x]]; }
	else dp0[x] = dp1[fa[x]],dp1[x] = dp0[fa[x]];
	for (int i = 0; i < G[x].size(); ++i) if (G[x][i] != fa[x]) dfs(G[x][i],x);
}
int cntw[N],cntl[N],sumww;
int dpf[N],dpg[N],cntf[N],cntg[N],sdp0[N],sdp1[N];
inline void upd(int &x,int y){ x = (x+y>=P)?(x+y-P):(x+y); }
inline void dpp1(int x){
	for (int y,i = 0; i < G[x].size(); ++i) if ((y=G[x][i])^fa[x]){
		dpp1(y),cntf[x] += cntf[y] == 0 ? 1 : 0;
		if (!cntf[y]) upd(sdp0[x],dpf[y]); else upd(sdp1[x],dpf[y]);
	}
	if (cntf[x] > 1) dpf[x] = 0; else if (cntf[x] == 1) dpf[x] = sdp0[x]; else dpf[x] = (1+sdp1[x]) % P;
}
inline void dpp2(int x){
	int y;
	if (y=fa[x]){
		if (y==1){
			int z = cntf[y] - (cntf[x]?0:1);
			if (z > 1) cntg[x] = z,dpg[x] = 0;
			else if (!z) cntg[x] = 0,dpg[x] = 1 + sdp1[y] - (cntf[x]?dpf[x]:0);
			else cntg[x] = 1,dpg[x] = sdp0[y] - (cntf[x]?0:dpf[x]);
		}
		else{
			int z = cntf[y] - (cntf[x]?0:1) + (cntg[y]?0:1);
			if (z > 1) cntg[x] = z,dpg[x] = 0;
			else if (!z) cntg[x] = 0,dpg[x] = 1 + sdp1[y] + dpg[y] - (cntf[x] ? dpf[x] : 0);
			else cntg[x] = 1,dpg[x] = cntg[y] ? (sdp0[y] - (cntf[x] ? 0 : dpf[x])) : dpg[y];
		}
	}
	if (x ^ 1){
		int s0 = sdp0[x],s1 = sdp1[x],ct = cntf[x] + (cntg[x] ? 0 : 1),ret = 0;
		if (!ct) ret = 1 + s1 + dpg[x];
		else if (ct == 1) ret = s0 + (cntg[x] ? 0 : dpg[x]);
		if (win[x]) sumww = (sumww + n-ret) % P; else sumww = (sumww + ret) % P;
	}
	else{ if (win[x]) sumww = (sumww + n-dpf[x]) % P; else sumww = (sumww + dpf[x]) % P; }
	for (int y,i = 0; i < G[x].size(); ++i) if ((y=G[x][i])^fa[x]) dpp2(y);
}
int sumll;
struct Mat{ int a00,a01,a10,a11; }T;
Mat operator * (Mat A,Mat B){
	static Mat T;
	T.a00 = ((LL)A.a00 * B.a00 + (LL)A.a01 * B.a10) % P,
	T.a01 = ((LL)A.a00 * B.a01 + (LL)A.a01 * B.a11) % P,
	T.a10 = ((LL)A.a10 * B.a00 + (LL)A.a11 * B.a10) % P,
	T.a11 = ((LL)A.a10 * B.a01 + (LL)A.a11 * B.a11) % P;
	return T;
}
Mat Power(Mat A,LL n){ Mat T; T.a00 = T.a11 = 1,T.a01 = T.a10 = 0; while (n){ if (n&1) T = T * A; A = A * A,n>>=1; } return T; }
int main(){
	int i,x,y,f0,f1;
	cin >> n >> d;
	for (i = 1; i < n; ++i) cin >> x >> y,G[x].push_back(y),G[y].push_back(x);
	fa[1] = 0,dfs1(1,0),dp11(1),dp22(1);
	for (i = 1; i <= n; ++i) if (DP(i,0)) win[i] = DP(i,0),++cntw[0]; else win[i] = 0,++cntl[0];
	dpp1(1),dpp2(1),sumll = ((LL)n * n % P - sumww + P) % P;
	fa[1] = 0,dfs1(1,0),dp11(1),dp22(1),dfs(1,0);
	T.a00 = (LL)n * cntw[0] % P,T.a01 = (LL)n * sumww % P,T.a10 = cntl[0],T.a11 = sumll,T = Power(T,d-1),f0 = T.a00,f1 = T.a10;
	int suml = 0,sumw = 0;
	suml = ((LL)sumll * f1 % P + (LL)cntl[0] * f0 % P) % P;
	sumw = ((LL)sumww * f1 % P + (LL)cntw[0] * f0 % P) % P;
	if (DP(1,0)) ans = (LL)n * sumw % P; else ans = 0;
	for (i = 1; i <= n; ++i) if (dp1[i]) ans = (ans + suml) % P;
	cout << ans << '\n';
	return 0;
}

标签:cntf,dpf,int,题解,迷航,else,CEOI2020,fa,dpg
来源: https://www.cnblogs.com/s-r-f/p/13591178.html