题解:P10646 [NordicOI 2023] ChatNOI
洛谷 P10646
题意
给定
对于一个句子
举个例子:
当这个文本的参数为
row row to the fishing rocks
out in the ocean they go
a cow is sitting and rowing
and the sun rises
and the sun sets
but the cow and the boat are still there
那么,句子 cow and the sun rises 的质量就是
其中,cow and the 出现了 and the sun 出现了 the sun rises 出现了
所以质量为
给定
请你给出方案。
思路
我们考虑构造答案的过程,对于每一个我们要填入的单词,实际上我们是只关心当前句子中最后的
譬如说当前的 a b c,那么当我们选择了单词 d 后,句子最末尾的 b c d。
我们可以将其视为 a b c 到 b c d 的一种转移。
像这样,我们可以将原文本中的每连续
我们用题面中给的文本举例:
row row to the fishing rocks
out in the ocean they go
a cow is sitting and rowing
and the sun rises
and the sun sets
but the cow and the boat are still there
那么,对于 and the 到 the sun 这样一条边,它的边权就是 and the sun 的出现次数为
像这样建完边以后,每个句子所对应的质量就是在这些有向边上移动时,所经过的边的边权的最小值。
然后我们就可以按照边权从大到小枚举,假设当前枚举的边权为
对于每一个未被解决的询问判断初始状态是否可以往外走
注意:当某一个询问的初始状态在一个环上,那么必定是可以无限走的,判断一下是否在拓扑排序时被遍历到即可。
这样的时间复杂度就是
然后我们会发现,这个边权是十分奇妙的,它所对应的是某个单词在某段连续
所以边权总和就是大约
因此,不同的边权的数量实际上就是大约
时间复杂度为 map 的复杂度。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int N = 5e5 + 10, INF = 1e9;
struct Edge {
int u, v, w, type;
bool operator < (const Edge &i) const {
return w > i.w;
}
};
int n, k, q, cnt, a[N], c, b[N], m[N], deg[N], query[N], dp[N];
pii trans[N];
map<string, int> mp;
map<vector<int>, int> tw;
vector<int> W, ans[N];
vector<pii> p[N], g[N], e[N];
vector<Edge> edge;
queue<int> que;
string to[N];
void topo_sort() {
fill(dp + 1, dp + c + 1, -INF);
for (int i = 1; i <= c; i++) if (!deg[i]) que.push(i), dp[i] = 0;
while (!que.empty()) {
int u = que.front(); que.pop();
for (auto [v, w] : g[u]) {
deg[v]--;
if (dp[u] + 1 > dp[v]) {
dp[v] = dp[u] + 1, trans[v] = {u, w};
}
if (!deg[v]) que.push(v);
}
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) {
string s; cin >> s;
if (!mp.count(s)) mp[s] = ++cnt, to[cnt] = s;
a[i] = mp[s];
}
for (int i = 1; i + k - 1 <= n; i++) {
vector<int> ts;
for (int j = i; j <= i + k - 1; j++) {
ts.push_back(a[j]);
}
if (!tw.count(ts)) tw[ts] = ++c;
b[i] = tw[ts];
if (i) p[b[i - 1]].push_back({b[i], a[i + k - 1]});
}
for (int i = 1; i <= c; i++) {
sort(p[i].begin(), p[i].end());
for (int j = 0; j < p[i].size(); ) {
pii t = p[i][j];
int ct = 0;
for (; j < p[i].size() && p[i][j] == t; j++) ct++;
edge.push_back({t.first, i, ct, t.second});
}
}
sort(edge.begin(), edge.end());
for (auto [u, v, w, tp] : edge) W.push_back(w);
sort(W.begin(), W.end());
W.erase(unique(W.begin(), W.end()), W.end());
cin >> q;
for (int i = 1; i <= q; i++) {
cin >> m[i];
vector<int> ts;
for (int j = 1; j <= k; j++) {
string s; cin >> s;
ts.push_back(mp[s]);
}
query[i] = (tw.count(ts) ? tw[ts] : -1);
}
reverse(W.begin(), W.end());
for (int ew : W) {
for (auto [u, v, w, tp] : edge) {
if (w < ew) break;
deg[v]++, g[u].push_back({v, tp});
e[v].push_back({u, tp});
}
topo_sort();
for (int i = 1; i <= q; i++) {
if (query[i] != -1 && deg[query[i]] && ans[i].empty()) {
int k = query[i];
while (ans[i].size() < m[i]) {
for (auto [t, d] : e[k]) {
if (deg[t]) {
k = t, ans[i].push_back(d);
break;
}
}
}
} else if (query[i] != -1 && dp[query[i]] >= m[i] && ans[i].empty()) {
int k = query[i];
while (ans[i].size() < m[i]) {
ans[i].push_back(trans[k].second);
k = trans[k].first;
}
}
}
for (int i = 1; i <= c; i++) deg[i] = 0, g[i].clear(), e[i].clear(), trans[i] = {0, 0};
}
for (int i = 1; i <= q; i++) {
if (query[i] == -1 || ans[i].empty()) {
while (m[i]--) cout << to[1] << ' ';
cout << '\n';
} else {
for (int x : ans[i]) cout << to[x] << ' ';
cout << '\n';
}
}
return 0;
}