Loading

【题解】CF1662C European Trip

\(n \le 100\) 个点的无向图,求有多少长度为 \(k\le 10^4\) 的从 \(x\) 出发的回路满足不存在一条边来回走的情况,即路径序列不存在 \(a\to b\to a\)。对每个 \(x\in[1,n]\) 求和。

实际上问题等价于对每个 \(x\) 求答案。

如果我们直接按题意模拟 DP,记录最后走的一条边,或者路径的倒数两个点可以轻易的做到 \(n^4k\)

事实上以上方法基本没有优化的余地,因为状态就已经非常大了。

考虑直接记录状态 \(f_{k,i,j}\) 表示从 \(i\)\(j\) 的长度为 \(k\) 的合法路径方案,然后用容斥统计答案。

显然 \(k=1\) 时就是邻接矩阵,\(k=2\) 时是邻接矩阵的平方减去度数矩阵。

对于 \(k>2\) 的情况,\(f_{k} = f_{k - 1} \times A - f_{k - 2}\times (D-I)\)

\(A\) 表示邻接矩阵,\(D\) 表示度数矩阵。这里减去单位矩阵 \(I\) 是因为倒数第二、三条边相等的情况不会被 \(f_{k - 1}\times A\) 算进去。

这样做可以做到 \(\mathcal{O}(n^3k)\),还是过不去。但是我们发现递推的形式是类似斐波那契的常系数齐次线性递推,只不过由整数变成了矩阵。幸运的是,矩阵套矩阵仍然可以矩阵快速幂,因为两个满足结合律的叠加仍然满足结合律,所以我们直接矩阵加速递推即可,只不过转移矩阵的元素仍是矩阵。时间复杂度 \(\mathcal{O}(n^3\log k)\)

How Linear Algebra's mind work?

#define N 105
int n, m, k;
struct node{
	int a[N][N];
}A, D, I, Z, S1, S2;
node operator*(node x, node y){
	node z; memset(z.a, 0, sizeof(z.a));
	rp(i, n)rp(j, n)rp(k, n)z.a[i][j] = (z.a[i][j] + x.a[i][k] * 1LL * y.a[k][j]) % P;
	return z;
}
node operator-(node x,node y){rp(i, n)rp(j, n)su(x.a[i][j], y.a[i][j]);return x;}
node operator+(node x,node y){rp(i, n)rp(j, n)ad(x.a[i][j], y.a[i][j]);return x;}
struct mat{node a[2][2];};
mat operator*(mat x, mat y){
	mat z; 
	z.a[0][0] = (x.a[0][0] * y.a[0][0]) + (x.a[0][1] * y.a[1][0]);
	z.a[0][1] = (x.a[0][0] * y.a[0][1]) + (x.a[0][1] * y.a[1][1]);
	z.a[1][0] = (x.a[1][0] * y.a[0][0]) + (x.a[1][1] * y.a[1][0]);
	z.a[1][1] = (x.a[1][0] * y.a[0][1]) + (x.a[1][1] * y.a[1][1]);
	return z;
}
mat operator^(mat x, int y){
	mat now; now.a[0][0] = now.a[1][1] = I, now.a[0][1] = now.a[1][0] = Z;
	for(; y; y >>= 1, x = x * x)if(y & 1)now = now * x;
	return now;
}
int main() {
	read(n, m, k);
	if(k <= 2){puts("0"); return 0;}
	rp(i, n)I.a[i][i] = 1;
	rp(i, m){
		int x, y;
		read(x, y);
		A.a[x][y] = A.a[y][x] = 1;
		D.a[x][x] ++, D.a[y][y] ++;
	}
	S1 = A, S2 = (A * A) - D;
	k -= 2; mat w; 
	w.a[0][0] = A, w.a[0][1] = I, w.a[1][0] = I - D, w.a[1][1] = Z;
	w = w ^ k;
	node cur = (S2 * w.a[0][0]) + (S1 * w.a[1][0]);
	int ans = 0;
	rp(i, n)ad(ans, cur.a[i][i]);
	printf("%d\n", ans);
	return 0;
}
posted @ 2022-04-26 16:42  7KByte  阅读(99)  评论(0编辑  收藏  举报