2023/3/17 做题技巧总结

1|0T1

对于一道题目, 如果描述有类似于“对于 x,yS 都有 xyS (其中 为任意满足交换律的运算)” 的描述时, 我们一定要想到的东西就是线性空间(因为两者的定义是相似的) , 然后我们可以考虑用特别的基来表示这个空间, 比如这道题, 我们就可以用线性基来表示, 然后考虑莫一位为主元的时候构造基里只有一个数这一位是 1 , 根据线性基的性质, 这一定是存在的, 并且是唯一的,然后又因为线性基所有数异或起来是空间最大值, 所以我们就能很容易的数位 DP 了

2|0T2

首先, 一棵树上满足什么条件, 在另一棵树上求值的题方法有很多, 但我觉得对于大部分题来说, 最好的方法还是对于一棵树保留他作为树, 而另一棵将其转化, 变成不是树或者能方便维护的问题。 比如这道题, 考虑第一棵树中取连通块, 这个连通块一定是一棵树, 那么如果有一个点的集合 S , 其导出子图满足点数 边数等于 1 , 则这是一个连通块。 所以我们就考虑每条边, 每个点对 T2 所有路径分别去贡献, 首先我们很明显能发现, 某条边 (u,v) 会对一些很有规律的路径做出贡献, 再仔细康康, 我们发现如果处理出 T2 每个点的 dfn, 那么对于 T1 中的边 (u,v) 来说, 在 T2 中找到 uv 这两个点, 那么能做贡献的边的两端一定在 uv 的子树中(如果 uv 在 T2 中一个为另一个的祖先, 那么有一端的点就不是在子树内, 而是在子树外), 两端分别在 O(1) 段连续的 dfn 序的段上, 那么考虑将 T2 上的一条路径用一个坐标 (dfn(u),dfn(v)) 来表示, 那么 T1 中的边 (u,v) 就对 O(1) 个矩形中的路径有贡献, 而点差不多同理, 对 O(deg(u)) 个矩形中的路径有贡献, 我们只要用一个数据结构, 实现可以 +11 的区间修改并且查询区间中 1 的数量, 当然, 矩阵, 无需在线, 都指向了一个方法 树套树 扫描线, 最后部分, 直接上扫描线维护即可

3|0T3

首先, 对于询问和与字符串上 lr 段相关的所有位置有关的问题, 我们一定要想到 SA 和 SAM , 当然, 如果你队 SAM 运用十分熟练, 完全不用考虑 SA 。 这道题两种方法都行, 当然 SAM 的漂亮方法我不会(SAM 我都不会/kk) , 所以我们直接考虑 SA 的方法。 首先我们需要想起一道非常经典的贪心问题, 校门外的树, 有了这个贪心的基础, 我们可以想到, 最多会填的 * 是 O(n/(rl+1)) 的, 那么有了这样一个东西, 我们能够想到更号分治, 这里有一个注意点, 我们考虑到了更号分治, 那么我们一定要想清楚小于更号的东西有哪些(一定要想全), 而且千万不要因为一个部分的思路影响了另一个部分的思路。 这道题对询问的区间长短分块, 如果小于更号, 那么预处理的时候用 map 或者 trie 树都可以搞过去。 然后对于大于的, 我们考虑 SA 最基本的性质就是两个位置的公共前缀长度, 等于排完序以后两个位置中间所有位置相邻两个之间公共前缀长度的最小值, 所以我们可以二分出有着 S[l...r] 这个前缀的位置排完序后是哪一段区间, 设这段区间为 (h,t), 然后对完成 SA 后的后缀位置, 建立主席树, 这样我们就可以知道 (h,t) 这段区间中有哪些位置了, 然后再进行贪心, 最后因为卡常, 所以块长要调整一下。
AC代码:

#include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <map> using namespace std; #define MAXN 100000 #define MAXM 20 #define INF 0x3f3f3f3f class suffix_array{ private: template <typename type> int* first_sort (type *s, type *end) { pair <type, int> *barrel_sort = new pair<type, int>[end - s]; int *barrel = new int[end - s]; for (type *i = s; i < end; i ++) { barrel_sort[i - s] = make_pair (*i, int (i - s)); } sort (barrel_sort, barrel_sort + int(end - s)); for (pair <type, int> *i = barrel_sort; i < barrel_sort + int(end - s); i ++) { barrel[i - barrel_sort] = i->second; } return barrel; } int query_rank (int *loc, int *end) { return loc >= end ? -1 : *loc; } public: template <typename type> int* Sort (type *s, type *end) { int *barrel = first_sort (s, end); int *barrel_end = new int[end - s]; int *temporary_barrel = new int[end - s]; int *rank = new int[end - s]; int num = 1; *(rank + *barrel) = 0; for (int *i = barrel + 1; i < barrel + int(end - s); i ++) { if (*(s + *i) != *(s + *(i - 1))) { barrel_end[num - 1] = i - barrel - 1; num ++; } *(rank + *i) = num - 1; } barrel_end[num - 1] = int(end - s) - 1; for (int len = 1; len < end - s; len <<= 1) { for (type *i = s; i < end; i ++) { temporary_barrel[i - s] = barrel[i - s]; } for (type *i = end - 1; i >= s; i --) { if (temporary_barrel[i - s] - len >= 0) { barrel[barrel_end[rank[temporary_barrel[i - s] - len]] --] = temporary_barrel[i - s] - len; } } for (int i = 0; i < len; i ++) { barrel[barrel_end[rank[i + int(end - s) - len]] --] = i + int(end - s) - len; } num = 1; for (int *i = barrel + 1; i < end - s + barrel; i ++) { if (*(rank + *i) != *(rank + *(i - 1)) || query_rank (rank + *i + len, rank + int(end - s)) != query_rank (rank + *(i - 1) + len, rank + int(end - s))) { barrel_end[num - 1] = i - barrel - 1; num ++; } } barrel_end[num - 1] = int(end - s) - 1; for (int t = 0, i = 0; t < num; t ++) { while (i <= barrel_end[t]) { rank[barrel[i]] = t; i ++; } } } return rank; } }sa; struct node { node *sonl = 0, *sonr = 0; int v = 0; }*rt[MAXN + 5]; struct trie { trie *next[26] = {}; pair<int, int> v; }*root; char c[MAXN +5]; int sloc[MAXN + 5]; int st[MAXN + 5][MAXM + 5]; int Log[MAXN + 5]; unsigned long long b[MAXN + 5], Hash[MAXN + 5]; map <unsigned long long, pair<int, int> > Map; long long find (int l, int r) { if (l > r) { return 0; } return Hash[r] - Hash[l - 1] * b[r - l + 1]; } int find_st (int l, int r) { if (l > r) { return INF; } else { int u = Log[r - l + 1]; return min (st[l][u], st[r - (1 << u) + 1][u]); } } node* change (node *p, int l, int r, int loc, int v) { node *new_p = new node; if (p) { *new_p = *p; } new_p->v += v; if (l == r) { return new_p; } int mid = (l + r) >> 1; if (loc <= mid) { new_p->sonl = change (new_p->sonl, l, mid, loc, v); } else { new_p->sonr = change (new_p->sonr, mid + 1, r, loc, v); } return new_p; } int ask (node *p, int l, int r, int h) { if (!p || p->v == 0) { return -1; } if (l == r) { return l; } int mid = (l + r) >> 1; if (h > mid) { return ask (p->sonr, mid + 1, r, h); } else { int v = ask (p->sonl, l, mid, h); if (~v) { return v; } else { return ask (p->sonr, mid + 1, r, h); } } } int ask (node *p1, node *p2, int l, int r, int h) { if (!p2) { return ask (p1, l, r, h); } if (!p1 || p1->v - p2->v == 0) { return -1; } if (l == r) { return l; } int mid = (l + r) >> 1; if (h > mid) { return ask (p1->sonr, p2->sonr, mid + 1, r, h); } else { int v = ask (p1->sonl, p2->sonl, l, mid, h); if (~v) { return v; } else { return ask (p1->sonr, p2->sonr, mid + 1, r, h); } } } int main () { freopen ("string.in", "r", stdin); freopen ("string.out", "w", stdout); int n, m; int Q; scanf ("%d %d", &n, &m); scanf ("%s", c + 1); b[0] = 1; for (int i = 1; i <= n; i ++) { b[i] = b[i - 1] * 13331; Hash[i] = Hash[i - 1] * 13331 + c[i]; } Log[0] = 0; Log[1] = 0; for (int i = 2; i <= n; i ++) { Log[i] = Log[i >> 1] + 1; } Q = max(1, int(sqrt (n * Log[n]))); int *s = sa.Sort (c + 1, c + 1 + n); for (int i = 0; i < n; i ++) { sloc[s[i]] = i; } for (int i = 1; i <= n; i ++) { rt[i] = change (rt[i - 1], 1, n, sloc[i - 1] + 1, 1); } for (int i = 1; i < n; i ++) { int l = 0, r = min (n - sloc[i - 1], n - sloc[i]); while (l < r) { int mid = (l + r + 1) >> 1; if (find (sloc[i - 1] + 1, sloc[i - 1] + mid) == find (sloc[i] + 1, sloc[i] + mid)) { l = mid; } else { r = mid - 1; } } st[i][0] = l; } for (int i = 1; i <= Log[n - 1]; i ++) { for (int j = 1; j < n - (1 << i) + 1; j ++) { st[j][i] = min (st[j][i - 1], st[j + (1 << (i - 1))][i - 1]); } } root = new trie; for (int i = 1; i <= n; i ++) { trie *p = root; if (!p->next[c[i] - 'a']) { p->next[c[i] - 'a'] = new trie; } p = p->next[c[i] - 'a']; for (int j = 2; j <= Q && j <= n - i + 1; j ++) { if (!p->next[c[i + j - 1] - 'a']) { p->next[c[i + j - 1] - 'a'] = new trie; } p = p->next[c[i + j - 1] - 'a']; if (p->v.second < i) { p->v.first ++; p->v.second = i + j - 2; } } } for (int i = 1; i <= m; i ++) { int l, r; scanf ("%d %d", &l, &r); if (l == r) { printf ("-1\n"); continue; } if (r - l + 1 > Q) { int hl = 0, hr = s[l - 1]; int tl = 0, tr = n - s[l - 1] - 1; while (hl < hr) { int mid = (hl + hr + 1) >> 1; if (find_st (s[l - 1] - mid + 1, s[l - 1]) >= r - l + 1) { hl = mid; } else { hr = mid - 1; } } while (tl < tr) { int mid = (tl + tr + 1) >> 1; if (find_st (s[l - 1] + 1, s[l - 1] + mid) >= r - l + 1) { tl = mid; } else { tr = mid - 1; } } int h = 0; int sum = 0; while (h <= n) { h = ask (rt[s[l - 1] + tr + 1], rt[s[l - 1] - hl], 1, n, h); if (!(~h)) { break; } h += (r - l); sum ++; } printf ("%d\n", sum); } else { trie *p = root; for (int j = l; j <= r; j ++) { p = p->next[c[j] - 'a']; } printf ("%d\n", p->v.first); } } }

被卡常的做法:

// ubsan: undefined // accoders #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <map> using namespace std; #define MAXN 100000 #define MAXM 20 #define INF 0x3f3f3f3f class suffix_array { private: template <typename type> int *first_sort(type *s, type *end) { pair<type, int> *barrel_sort = new pair<type, int>[end - s]; int *barrel = new int[end - s]; for (type *i = s; i < end; i++) { barrel_sort[i - s] = make_pair(*i, int(i - s)); } sort(barrel_sort, barrel_sort + int(end - s)); for (pair<type, int> *i = barrel_sort; i < barrel_sort + int(end - s); i++) { barrel[i - barrel_sort] = i->second; } return barrel; } int query_rank(int *loc, int *end) { return loc >= end ? -1 : *loc; } public: template <typename type> int *Sort(type *s, type *end) { int *barrel = first_sort(s, end); int *barrel_end = new int[end - s]; int *temporary_barrel = new int[end - s]; int *rank = new int[end - s]; int num = 1; *(rank + *barrel) = 0; for (int *i = barrel + 1; i < barrel + int(end - s); i++) { if (*(s + *i) != *(s + *(i - 1))) { barrel_end[num - 1] = i - barrel - 1; num++; } *(rank + *i) = num - 1; } barrel_end[num - 1] = int(end - s) - 1; for (int len = 1; len < end - s; len <<= 1) { for (type *i = s; i < end; i++) { temporary_barrel[i - s] = barrel[i - s]; } for (type *i = end - 1; i >= s; i--) { if (temporary_barrel[i - s] - len >= 0) { barrel[barrel_end[rank[temporary_barrel[i - s] - len]]--] = temporary_barrel[i - s] - len; } } for (int i = 0; i < len; i++) { barrel[barrel_end[rank[i + int(end - s) - len]]--] = i + int(end - s) - len; } num = 1; for (int *i = barrel + 1; i < end - s + barrel; i++) { if (*(rank + *i) != *(rank + *(i - 1)) || query_rank(rank + *i + len, rank + int(end - s)) != query_rank(rank + *(i - 1) + len, rank + int(end - s))) { barrel_end[num - 1] = i - barrel - 1; num++; } } barrel_end[num - 1] = int(end - s) - 1; for (int t = 0, i = 0; t < num; t++) { while (i <= barrel_end[t]) { rank[barrel[i]] = t; i++; } } } return rank; } } sa; struct node { node *sonl = 0, *sonr = 0; int v = 0; } * rt[MAXN + 5]; char c[MAXN + 5]; int sloc[MAXN + 5]; int st[MAXN + 5][MAXM + 5]; int Log[MAXN + 5]; unsigned long long b[MAXN + 5], Hash[MAXN + 5]; map<unsigned long long, pair<int, int> > Map; long long find(int l, int r) { if (l > r) { return 0; } return Hash[r] - Hash[l - 1] * b[r - l + 1]; } int find_st(int l, int r) { if (l > r) { return INF; } else { int u = Log[r - l + 1]; return min(st[l][u], st[r - (1 << u) + 1][u]); } } node *change(node *p, int l, int r, int loc, int v) { node *new_p = new node; if (p) { *new_p = *p; } new_p->v += v; if (l == r) { return new_p; } int mid = (l + r) >> 1; if (loc <= mid) { new_p->sonl = change(new_p->sonl, l, mid, loc, v); } else { new_p->sonr = change(new_p->sonr, mid + 1, r, loc, v); } return new_p; } int ask(node *p, int l, int r, int h) { if (!p || p->v == 0) { return -1; } if (l == r) { return l; } int mid = (l + r) >> 1; if (h > mid) { return ask(p->sonr, mid + 1, r, h); } else { int v = ask(p->sonl, l, mid, h); if (~v) { return v; } else { return ask(p->sonr, mid + 1, r, h); } } } int ask(node *p1, node *p2, int l, int r, int h) { if (!p2) { return ask(p1, l, r, h); } if (!p1 || p1->v - p2->v == 0) { return -1; } if (l == r) { return l; } int mid = (l + r) >> 1; if (h > mid) { return ask(p1->sonr, p2->sonr, mid + 1, r, h); } else { int v = ask(p1->sonl, p2->sonl, l, mid, h); if (~v) { return v; } else { return ask(p1->sonr, p2->sonr, mid + 1, r, h); } } } int main() { freopen("string.in", "r", stdin); freopen("string.out", "w", stdout); int n, m; int Q; scanf("%d %d", &n, &m); Q = sqrt(n); scanf("%s", c + 1); b[0] = 1; for (int i = 1; i <= n; i++) { b[i] = b[i - 1] * 13331; Hash[i] = Hash[i - 1] * 13331 + c[i]; } Log[0] = 0; Log[1] = 0; for (int i = 2; i <= n; i++) { Log[i] = Log[i >> 1] + 1; } int *s = sa.Sort(c + 1, c + 1 + n); for (int i = 0; i < n; i++) { sloc[s[i]] = i; } for (int i = 1; i <= n; i++) { rt[i] = change(rt[i - 1], 1, n, sloc[i - 1] + 1, 1); } for (int i = 1; i < n; i++) { int l = 0, r = min(n - sloc[i - 1], n - sloc[i]); while (l < r) { int mid = (l + r + 1) >> 1; if (find(sloc[i - 1] + 1, sloc[i - 1] + mid) == find(sloc[i] + 1, sloc[i] + mid)) { l = mid; } else { r = mid - 1; } } st[i][0] = l; } for (int i = 1; i <= Log[n - 1]; i++) { for (int j = 1; j < n - (1 << i) + 1; j++) { st[j][i] = min(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]); } } for (int i = 1; i <= n; i++) { for (int j = 2; j <= Q && j <= n - i + 1; j++) { unsigned long long v = find(i, i + j - 1); map<unsigned long long, pair<int, int> >::iterator it = Map.find(v); if (it == Map.end()) { Map.insert(make_pair(v, make_pair(1, i + j - 2))); } else if (it->second.second < i) { it->second.first++; it->second.second = i + j - 2; } } } for (int i = 1; i <= m; i++) { int l, r; scanf("%d %d", &l, &r); if (l == r) { printf("-1\n"); continue; } if (r - l + 1 > Q) { int hl = 0, hr = s[l - 1]; int tl = 0, tr = n - s[l - 1] - 1; while (hl < hr) { int mid = (hl + hr + 1) >> 1; if (find_st(s[l - 1] - mid + 1, s[l - 1]) >= r - l + 1) { hl = mid; } else { hr = mid - 1; } } while (tl < tr) { int mid = (tl + tr + 1) >> 1; if (find_st(s[l - 1] + 1, s[l - 1] + mid) >= r - l + 1) { tl = mid; } else { tr = mid - 1; } } int h = 0; int sum = 0; while (h <= n) { h = ask(rt[s[l - 1] + tr + 1], rt[s[l - 1] - hl], 1, n, h); if (!(~h)) { break; } h += (r - l); sum++; } printf("%d\n", sum); } else { printf("%d\n", Map[find(l, r)].first); } } }

__EOF__

本文作者FlowerDream
本文链接https://www.cnblogs.com/flower-dream/p/17228370.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   小篪篪  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
Live2D
欢迎阅读『2023/3/17 做题技巧总结』
点击右上角即可分享
微信分享提示