题解:P17421 [ICPC 2018 Xuzhou R] Rikka with Subsequences

这种唐题卡那么久吗,我无敌了。

\(\sum cnt^3\) 用组合意义化掉,问题转化成求选出三个值相同的 Yuta 子序列的方案数。

直接 DP,令 \(f_{i,j,k}\) 表示三个子序列分别以 \(a_i,a_j,a_k\) 结尾时的方案数。暴力转移显然:

\[f_{i,j,k}=\sum_{\substack{p<i,q<j,r<k\\M_{a_p,a_i}=1}} f_{p,q,r} \]

考虑把其中一维拆出来处理 \(M\) 的限制。处理出

\[g_{i,j,k}=\sum_{\substack{r<k\\M_{a_r,a_k}=1}}f_{i,j,r} \]

那么我们对 \(g\)\(i,j\) 两维做二维前缀和即可 \(\mathcal{O}(1)\) 转移 \(f\)

考虑如何快速求出 \(g_{i,j,k}\)。观察到 \(f_{i,j,r}\) 有值时必有 \(a_i=a_r\),于是若 \(M_{a_i,a_k}=0\),则 \(g_{i,j,k}=0\),否则

\[g_{i,j,k}=\sum_{\substack{r<k\\a_i=a_r}}f_{i,j,r} \]

从小到大枚举 \(k\) 的过程中直接计算即可。

时间复杂度为 \(\mathcal{O}(Tn^3)\)

主要代码
int tc, n, a[MAXN];
bool M[MAXN][MAXN];
mint f[2][MAXN][MAXN], g[2][MAXN][MAXN], h[2][MAXN][MAXN];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	cin >> tc;
	while (tc--) {
		cin >> n;
		for (int i = 1; i <= n; ++i) cin >> a[i];

		for (int i = 1; i <= n; ++i) {
			string s;
			cin >> s;
			for (int j = 1; j <= n; ++j) M[i][j] = s[j - 1] - '0';
		}

		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= n; ++j) {
				f[0][i][j] = f[1][i][j] = 0;
				g[0][i][j] = g[1][i][j] = 0;
				h[0][i][j] = h[1][i][j] = 0;
			}
		}

		mint ans = 0;
		for (int i = 1; i <= n; ++i) {
			int cur = i & 1, prv = cur ^ 1;
			for (int j = 1; j <= n; ++j) {
				mint sum = 0;
				for (int k = 1; k <= n; ++k) {
					f[cur][j][k] = 0;
					g[cur][j][k] = M[a[i]][a[k]] ? sum : 0;
					h[cur][j][k] = h[prv][j][k] + h[cur][j - 1][k] - h[prv][j - 1][k] + g[cur][j][k];
					if (a[i] != a[j] || a[j] != a[k]) continue;
					f[cur][j][k] = h[prv][j - 1][k] + 1;
					ans += f[cur][j][k];
					sum += f[cur][j][k];
				}
			}
		}
		cout << ans << '\n';
	}
	return 0;
}
posted @ 2026-09-11 14:08  P2441M  阅读(8)  评论(0)    收藏  举报