10.14
看大家得分跟信心赛似的,就我一个唐诗写了一场暴力 \(\ldots\)
开场t1没切出来就开始慌了,之后就想着多打暴力拿部分分,导致t2得出的性质没有推广,t3,t4暴力都没写出来(这俩得出性质/部分性质后比暴力好写多了)\(\ldots\)
t1
看到题就想二分,结果根本就分不出来 \(\ldots\)
发现我好像对于在线查询有种别样的执着,每次都不会离线和预处理 \(\ldots\)
观察到值域很小,空间可接受,于是直接一个 \(O(nV)\) 巨大预处理,之后单次询问是 \(O(\log(n)\log(V))\) ,所以总复杂度为 \(O(nV+q\log(n)\log(V))\)(其实还有单log做法)。
预处理:对于每个 \(x\) ,记录所有 \(x|a_i=x\) 的 \(i\) ,查询时二分查找即可。
code
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 10;
int n, q;
int a[N], b[N];
vector<int> f[1024];inline long long solve(int l, int r, int x)
{long long ans = 0;int now = l;while (now <= r){// cerr << "&\n";if (f[x].size() == 0 || f[x][f[x].size() - 1] < now)break;// cerr << "!\n";int id = *lower_bound(f[x].begin(), f[x].end(), now);if (id > r)break;// int nxt = f[x][id];ans += b[id], x -= a[id];now = id + 1;// cerr << "id=" << id << " now=" << now << "\n";}// cerr << "$ans=" << ans << "\n";return ans;
}signed main()
{
#ifndef ANSfreopen("expedition.in", "r", stdin);freopen("expedition.out", "w", stdout);
#elsefreopen("ex_expedition1.in", "r", stdin);freopen("1.out", "w", stdout);
#endifios::sync_with_stdio(0);cin.tie(0);cin >> n;for (int i = 1; i <= n; ++i){cin >> a[i];for (int val = a[i]; val <= 1023; ++val){if ((val | a[i]) == val)f[val].emplace_back(i);}}for (int i = 1; i <= n; ++i)cin >> b[i];cin >> q;int l, r, x;long long ans = 0;while (q--){cin >> l >> r >> x;ans ^= solve(l, r, x);}cout << ans;return 0;
}
t2
树的性质是好观察的,层数之差为奇数答案为 1 ,否则答案为 2 。
其实继续思考(或观察大阳历)就能发现答案只有 \(-1,0,1,2\) 但是我当时甚至都没有多看那两个非树的大阳历一眼 \(\ldots\)
继续推广可知,当两点间距离为奇数时,答案为 1 ,否则为 2 (在同一连通块内)。
考虑加边:满3加边,若存在奇环,则块内任意两点都可通过环改变这两点路径的奇偶性(画图可知)。
因此重点为判奇环。
奇偶染色即可。
具体看代码
code
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int T, n, m, q, cnt;
vector<int> e[N];
bool flag[N], gd[N];
int col[N], belong[N];void dfs(int x, int pre)
{belong[x] = cnt;if (col[x] && col[x] != pre)gd[cnt] = 1;elsecol[x] = pre;flag[x] = 1;for (auto y : e[x]){if (col[y] && col[y] == pre)gd[cnt] = 1;if (flag[y])continue;dfs(y, ((pre - 1) ^ 1) + 1);}
}signed main()
{freopen("teleport.in", "r", stdin);freopen("teleport.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cin >> T;cin >> n >> m;for (int i = 1, u, v; i <= m; ++i){cin >> u >> v;e[u].push_back(v);e[v].push_back(u);}for (int i = 1; i <= n; ++i){if (!flag[i])++cnt, dfs(i, 1);}// for (int i = 1; i <= n; ++i)// cerr << col[i] << "\n";// cerr << gd[1] << "\n";cin >> q;int s, t;while (q--){cin >> s >> t;if (s == t){cout << 0 << "\n";continue;}if (belong[s] != belong[t]){cout << -1 << "\n";continue;}if (gd[belong[s]]){cout << 1 << "\n";continue;}if (col[s] != col[t])cout << 1 << "\n";elsecout << 2 << "\n";}return 0;
}
t3
这题我觉得简单思考就解决了,但我当时一心暴力。
限制转化为形如 xxyzxy
之后暴力枚举 x,y,z 即可。
60pts
考虑到对于 z 只要求与 x,y 不同即可,根本不用枚举。
于是\(O(nk^2)\) ,通过。
code
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int mod = 114514;
string s;
int n, ans;inline int sum(int x)
{if (x >= mod)return x - mod;return x;
}inline void solve(char x, char y)
{int len1 = 0, len2 = 0, len3 = 0, len4 = 0, len5 = 0, len6 = 0;for (int i = 1; i <= n; ++i){if (s[i] == x){len5 += len4, len2 += len1, ++len1;len5 = sum(len5), len2 = sum(len2), len1 = sum(len1);}else if (s[i] == y){len6 += len5, len3 += len2;len6 = sum(len6), len3 = sum(len3);}else{len4 += len3;len4 = sum(len4);}}ans += len6;ans = sum(ans);
}signed main()
{freopen("anc.in", "r", stdin);freopen("anc.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cin >> s;n = s.size();s = " " + s;for (int i = 1; i <= 26; ++i)for (int j = 1; j <= 26; ++j){if (i == j)continue;solve((char)i + 'a' - 1, (char)j + 'a' - 1);}cout << (ans + mod) % mod;return 0;
}