NordicOI 2023
A. ChatNOI
题目描述
给定一个由
思路
因为我们是不断在后面加入单词,所以我们可以把这个文章变成一个图。每个的字串
这里很显然点,边和边权总和的数量级都是
这个有什么用呢?我们可以暴力从大到小枚举每种边权
空间复杂度
代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int MAXN = 500001, MAXQ = 100001, INF = INT_MAX;
const ll b[2] = {29, int(1e9) + 9}, MOD = int(1e9) + 7;
struct query {
int m, id;
ull x;
}a[MAXQ];
int n, k, tot, q, in[MAXN], dp[MAXN], f[MAXN], fid[MAXN];
ull sum[MAXN], Pow[MAXN];
string S[MAXN];
map<ull, int> mp, cnt;
vector<tuple<int, int, int>> e[MAXN];
vector<int> ve, ans[MAXQ];
vector<tuple<int, int, int, int>> vec;
int Hash(const string &s) {
int ret = 0;
for(char c : s) {
ret = (1ll * ret * b[0] % MOD + c - 'a' + 1) % MOD;
}
return ret;
}
ull Calc(int l, int r) {
return sum[r] - sum[l - 1] * Pow[r - l + 1];
}
void topo_sort() {
queue<int> que;
fill(in + 1, in + tot + 1, 0);
for(int i = 1; i <= tot; ++i) {
dp[i] = 0;
for(auto [v, w, id] : e[i]) {
in[v]++;
}
}
for(int i = 1; i <= tot; ++i) {
if(!in[i]) {
que.push(i);
}
}
for(; !que.empty(); ) {
int u = que.front();
que.pop();
for(auto [v, w, id] : e[u]) {
if(dp[u] + 1 > dp[v]) {
dp[v] = dp[u] + 1, f[v] = u, fid[v] = id;
}
if(!(--in[v])) {
que.push(v);
}
}
}
for(int i = 1; i <= tot; ++i) {
if(in[i]) {
dp[i] = INF;
for(auto [v, w, id] : e[i]) {
if(in[v]) {
f[v] = i, fid[v] = id;
}
}
}
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> k;
Pow[0] = 1;
for(int i = 1; i <= n; ++i) {
string s;
cin >> s;
S[i] = s;
sum[i] = sum[i - 1] * b[1] + Hash(s);
Pow[i] = Pow[i - 1] * b[1];
}
for(int i = 1; i <= n - k; ++i) {
cnt[Calc(i, i + k)]++;
}
for(int i = 1; i <= n - k + 1; ++i) {
ull h = Calc(i, i + k - 1);
if(!mp.count(h)) {
mp[h] = ++tot;
}
if(i > 1) {
vec.emplace_back(cnt[Calc(i - 1, i + k - 1)], mp[Calc(i - 1, i + k - 2)], mp[h], i + k - 1);
ve.emplace_back(cnt[Calc(i - 1, i + k - 1)]);
}
}
cin >> q;
for(int i = 1; i <= q; ++i) {
cin >> a[i].m;
for(int j = 1; j <= k; ++j) {
string s;
cin >> s;
a[i].x = a[i].x * b[1] + Hash(s);
}
a[i].x = mp[a[i].x];
}
sort(ve.begin(), ve.end()), ve.erase(unique(ve.begin(), ve.end()), ve.end()), reverse(ve.begin(), ve.end());
sort(vec.begin(), vec.end(), greater<tuple<int, int, int, int>>());
int j = 0;
for(int x : ve) {
for(; j < int(vec.size()); ++j) {
auto [w, u, v, id] = vec[j];
if(w >= x) {
e[v].emplace_back(u, w, id);
}else {
break;
}
}
topo_sort();
for(int i = 1; i <= q; ++i) {
if(!a[i].x || ans[i].size() || dp[a[i].x] < a[i].m) {
continue;
}
int u = a[i].x, cnt = 1;
for(; cnt <= a[i].m; u = f[u], cnt++) {
ans[i].emplace_back(fid[u]);
}
}
}
for(int i = 1; i <= q; ++i) {
if(ans[i].empty()) {
for(int j = 1; j <= a[i].m; ++j) {
cout << S[1] << " \n"[j == a[i].m];
}
}else {
for(int x : ans[i]) {
cout << S[x] << " ";
}
cout << "\n";
}
}
return 0;
}
B. Ice Cream Machines
题目描述
有
求至少要清洗几次。
思路
用贪心解决。我们用 set
记录每个冰淇凌机当前是什么冰淇凌,该冰淇凌下次出现的位置,我们肯定会选择下次出现位置更靠后的清洗。
空间复杂度
代码
#include<bits/stdc++.h>
using namespace std;
using pii = pair<int, int>;
const int MAXN = 200001, MAXM = 200001, MAXK = 200001;
int n, m, k, c[MAXN], cnt[MAXM], a[MAXK], pos[MAXM], ans;
set<pii, greater<pii>> s;
vector<int> ve[MAXM];
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m >> k;
for(int i = 1; i <= n; ++i) {
cin >> c[i];
ve[c[i]].emplace_back(i);
}
for(int i = 1; i <= m; ++i) {
ve[i].emplace_back(n + 1);
}
for(int i = 1; i <= k; ++i) {
s.insert({n + 1, i});
}
for(int i = 1; i <= n; ++i) {
if(!pos[c[i]]) {
ans++;
auto [cur, p] = *s.begin();
s.erase(s.begin());
s.insert({*upper_bound(ve[c[i]].begin(), ve[c[i]].end(), i), p});
pos[a[p]] = 0;
pos[c[i]] = p;
a[p] = c[i];
}else {
s.erase({i, pos[c[i]]});
s.insert({*upper_bound(ve[c[i]].begin(), ve[c[i]].end(), i), pos[c[i]]});
}
}
cout << ans;
return 0;
}
本文作者:yaosicheng124
本文链接:https://www.cnblogs.com/yaosicheng124/p/18473776
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步