20240705

T1

NFLSOJ P5030 最小表示

考虑两个串本质相同的条件,发现如果计算出每一位上的字母距离它上一次出现的距离 \(dis_i\),那两个串本质相同等价于所有 \(dis_i\) 相同。注意到这个东西只和相对位置有关,所以只需要先对原串求一遍 \(dis\) 数组,然后对这个 \(dis\) 数组后缀排序一下,求出本质不同子串数即可。

但是这个事情很显然是不对的,因为比如说对于 \(\texttt{abcabcbac}\),对原串求 \(dis\) 得到 \(\{ 1, 2, 3, 2, 2, 2, 1, 3, 2 \}\),而如果考虑 \(\texttt{cbac}\) 这个后缀,\(dis\) 就变成了 \(\{ 1, 2, 3, 2 \}\)。容易发现这里对应位置上的 \(dis\) 值发生了变化。这实际上是由于后缀的起始点分隔了某些字母的相邻两次出现,从而导致后面那次出现的 \(dis\) 发生变化。注意到如果把这些发生变化的 \(dis\) 值全部变成 \(0\),也不会影响子串同构的判断。因此对于每个后缀直接把这些位置归零,然后把处理之后的后缀做后缀排序。注意,这里每个后缀是独立处理的,它们各自独立将自己的对应位置归零。

接下来考虑如何对处理之后的后缀做后缀排序。由于每个后缀是独立更改的,我们并不能很容易地完成排序。但是注意到字母只有 \(10\) 个,也就是 \(0\) 位置至多只有 \(10\) 个。因此可以对每个后缀记录该后缀的所有 \(0\) 位置,然后使用二分 + 哈希比较两个子串的字典序。如果没有删除位置,直接哈希即可。对于删除位置,由于数量很小,暴力枚举所有删除位置,将这一位对于哈希值的贡献减去即可。

完成后缀排序之后,直接根据 SA 求本质不同子串数的套路拿总共的减去每两个排名相邻的后缀的 LCP 即可。

代码
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int B = 233333;
const int P = 1000000007;
int a[50005], n, m;
string str;
int ap[15], aft[50005][15];
int del[50005][15];
int hsh[50005];
int pw[50005], lst[50005];
int ord[50005];
int Query(int l, int r) { return (P + hsh[r] - hsh[l - 1] * pw[r - l + 1] % P) % P; }
int chk(int l, int r) {int ret = Query(l, r);for (int i = 1; i <= del[l][0]; i++) {if (del[l][i] <= r) ret = (P + ret - pw[r - del[l][i]] * a[del[l][i]] % P) % P;}return ret;
}
int lcp(int a, int b) {int l = 1, r = n - max(a, b) + 1, mid, ans = 0;while (l <= r) {mid = (l + r) >> 1;if (chk(a, a + mid - 1) == chk(b, b + mid - 1)) ans = mid, l = mid + 1;else r = mid - 1;}return ans;
}
int q(int x, int y) {int ax = a[y];for (int i = 1; i <= del[x][0]; i++) del[x][i] == y ? (ax = 0) : 0;return ax;
}
bool cmp(int a, int b) {int ans = lcp(a, b);if (ans == n - max(a, b) + 1) return a > b;else return q(a, a + ans) < q(b, b + ans);
}
signed main() {freopen("string.in", "r", stdin);freopen("string.out", "w", stdout);cin >> n >> m;pw[0] = 1;for (int i = 1; i <= n; i++) pw[i] = pw[i - 1] * B % P;cin >> str;str = ' ' + str;for (int i = 1; i <= n; i++) {a[i] = i - ap[str[i] - 'a'];hsh[i] = (hsh[i - 1] * B + a[i]) % P;lst[i] = ap[str[i] - 'a'];ap[str[i] - 'a'] = i;for (int j = lst[i] + 1; j <= i; j++) aft[j][str[i] - 'a'] = i;}for (int i = 1; i <= n; i++) {for (int j = 0; j < m; j++) {if (aft[i][j]) del[i][++del[i][0]] = aft[i][j];}}for (int i = 1; i <= n; i++) ord[i] = i;sort(ord + 1, ord + n + 1, cmp);int ans = n * (n + 1) / 2;for (int i = 1; i < n; i++) ans -= lcp(ord[i], ord[i + 1]);cout << ans << "\n";return 0;
}

T3

NFLSOJ P3361 模板性二维数点

考虑所有黑点的纵坐标都小于白点的纵坐标时会发生什么。此时我们选出的答案里必然包含黑点权值的最大值或白点权值的最大值。如果两个点可以同时选,则显然正确。否则对于任意一组解,把其中一个换成对应的权值最大值必然更优。

因此考虑对纵坐标分治,每次考虑纵坐标在分治中心之下的黑点和纵坐标在分治中心之上的白点,根据结论我们可以在这一层中选出 \(O(区间长度)\) 个有效(可能成为答案)的点对。分治有 \(O(\log n)\) 层,因此有用点对的级别在 \(O(n \log n)\)。这样就可以对每个询问离线做二维数点了。

代码
#include <iostream>
#include <algorithm>
#include <cassert>
#include <vector>
#include <map>
#define lowbit(x) ((x) & (-(x)))
using namespace std;
int n, q;
struct Point {int x, y, w;
} val[3000005], a[100005], b[100005];
int vcnt;
struct Query {int l, r, id;
} qs[500005];
vector<Point> va;
vector<Point> vb;
int d[1200005], dcnt;
map<int, int> mp;
void Solve(int l, int r, vector<Point> v1, vector<Point> v2) {if (v1.empty() || l >= r) return;int mid = (l + r) >> 1;vector<Point> va1, va2, vb1, vb2;for (auto p : v1) (p.y <= mid ? va1 : va2).emplace_back(p);for (auto p : v2) (p.y <= mid ? vb1 : vb2).emplace_back(p);if (va1.size() && vb2.size()) {Point p1, p2;p1.w = p2.w = 0;for (auto p : va1) p.w > p1.w ? (p1 = p) : p;for (auto p : vb2) {p.w > p2.w ? (p2 = p) : p;val[++vcnt] = (Point) { p1.x, p.x, p1.w + p.w };}for (auto p : va1) p.x != p1.x ? (val[++vcnt] = (Point) { p.x, p2.x, p.w + p2.w }) : p1;}Solve(l, mid, va1, vb1);Solve(mid + 1, r, va2, vb2);
}
struct BIT {int bit[1000005];void add(int x, int y) { for (; x <= 1000000; x += lowbit(x)) bit[x] = max(bit[x], y); }int query(int x) {int ret = 0;for (; x; x -= lowbit(x)) ret = max(ret, bit[x]);return ret;}
} bit;
struct SBIT {int bit[1000005];void add(int x, int y) { for (; x; x -= lowbit(x)) bit[x] = max(bit[x], y); }int query(int x) {int ret = 0;for (; x <= 1000000; x += lowbit(x)) ret = max(ret, bit[x]);return ret;}
} bit2;
int ans[500005];
int main() {freopen("template.in", "r", stdin);freopen("template.out", "w", stdout);cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i].x >> a[i].y >> a[i].w;}for (int i = 1; i <= n; i++) {cin >> b[i].x >> b[i].y >> b[i].w;}cin >> q;for (int i = 1; i <= q; i++) cin >> qs[i].l >> qs[i].r, qs[i].id = i;for (int i = 1; i <= n; i++) d[++dcnt] = a[i].x, d[++dcnt] = b[i].x;for (int i = 1; i <= q; i++) d[++dcnt] = qs[i].l, d[++dcnt] = qs[i].r;d[++dcnt] = 0;sort(d + 1, d + dcnt + 1);d[0] = 2147483647;mp[d[0]] = -n - q - 1;for (int i = 1; i <= dcnt; i++) d[i] != d[i - 1] ? (mp[d[i]] = mp[d[i - 1]] + 1) : 0;for (int i = 1; i <= n; i++) a[i].x = mp[a[i].x], b[i].x = mp[b[i].x];for (int i = 1; i <= q; i++) qs[i].l = mp[qs[i].l], qs[i].r = mp[qs[i].r];dcnt = 0;for (int i = 1; i <= n; i++) d[++dcnt] = a[i].y, d[++dcnt] = b[i].y;sort(d + 1, d + dcnt + 1);mp.clear();for (int i = 1; i <= dcnt; i++) d[i] != d[i - 1] ? (mp[d[i]] = mp[d[i - 1]] + 1) : 0;for (int i = 1; i <= n; i++) a[i].y = mp[a[i].y], b[i].y = mp[b[i].y];for (int i = 1; i <= n; i++) {va.emplace_back(a[i]);vb.emplace_back(b[i]);}Solve(1, n * 2, va, vb);sort(val + 1, val + vcnt + 1, [](Point a, Point b) { return a.x < b.x; });sort(qs + 1, qs + q + 1, [](Query a, Query b) { return a.l < b.l; });for (int i = 1, j = 1; i <= q; i++) {while (j <= vcnt && val[j].x < qs[i].l) bit2.add(val[j].y, val[j].w), ++j;ans[qs[i].id] = bit2.query(qs[i].r);}for (int i = q, j = vcnt; i; i--) {while (j > 0 && val[j].x > qs[i].l) bit.add(val[j].y, val[j].w), --j;ans[qs[i].id] = max(ans[qs[i].id], bit.query(qs[i].r));}for (int i = 1; i <= q; i++) cout << (ans[i] == 0 ? -1 : ans[i]) << "\n";return 0;
}

考虑可能对答案有贡献的元素。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/739776.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

24-暑假软件工程日报(7_7)

工作时间:7月7日 14:00-17:00 工作内容: 基本完成第二阶段大程序构建 代码:#include <cstring> #include <iostream> #include <list> #include <math.h> #include <queue> #include <stack> #include <stdio.h> #include <st…

[CISCN2019 华北赛区 Day2 Web1]Hack World

进入题目 输入数字1数字20对select 空格 union or 等等测试发现没有过滤select 空格也被过滤 注意不能单独测试用亦或运算 1^0为真 尝试0^if((ascii(substr((select(flag)from(flag)),1,1))=100),0,1) 回显正常根据回显判断正误 编写脚本爆破,由于该网站请求太快会报429,请求…

CubeMx的部分配置显示不出来

现象描述:CubeMx的部分配置显示不出来 处理方法:(1)继续进行其他配置,给工程起名字,并生成代码;(2)关闭CubeMx后再次打开

[CISCN2019 华东南赛区]Double Secret

进入题目由于请求不能过快,目录扫描工具失效可写脚本, 根据题目两个secret,猜测有serect目录 访问猜测还有一个secret参数随意输入发现源码泄露 注意到有flask,考虑python模板注入 注意到发现rc4加密 找师傅的加密脚本 import base64 from urllib.parse import quote def rc4…

[CISCN2019 华东南赛区]Web11

进入题目注意到xff 在url处随意输入目录xff随之变化 注意下放smarty是php模板 猜测xff为模板注入点 如下用if标签看到回显得到flag flag{6efda977-94fb-4d30-8668-fe28458ec2bf}

game1

进入题目发现是一个游戏发现有一个score.php的发包 发现有分数等 对比不同分数的包发现sign值都有ZM后疑似为base64于是将分数改为较高的分,ZM+base64 尝试要补一个=得到flag

[CISCN 2019 初赛]Love Math

进入题目,直接源码 代码审计、看师傅wp有黑名单字符过滤,有白名单函数过滤 于是用编码绕过,利用eval函数执行命令,system(cat /flag.txt) base_convert(a,b,c) //将数值a按b进制转换为c进制 dechex //将10进制转成16进制 hex2bin() //16进制转成字符串 base_convert(37907…

babyweb国赛华东北

进入题目目录扫描 扫出ssrf.php 发现url尝试用file协议访问/flag.txt拿到flag

人脸识别签到系统一站式开发【基于Pyqt5的CS架构软件】

人脸识别签到系统:课堂签到,上班打卡,进出门身份验证。 功能:人脸录入,打卡签到,声音提醒,打卡信息导出,打包exe文件人脸识别签到系统 1、运用场景 课堂签到,上班打卡,进出门身份验证。 2、功能架构 人脸录入,打卡签到,声音提醒,打卡信息导出:3、技术栈 python3.8…

本地管理员

进入题目 随意输入密码发现提示ip,则尝试xff伪造ip右键检查发现base64编码 解码得猜测为用户admin密码 抓包发包得到flag

rust学习-记录第一个完成的rust算法题

给你一个下标从 0 开始的 8 x 8 网格 board ,其中 board[r][c] 表示游戏棋盘上的格子 (r, c) 。棋盘上空格用 . 表示,白色格子用 W 表示,黑色格子用 B 表示。 游戏中每次操作步骤为:选择一个空格子,将它变成你正在执行的颜色(要么白色,要么黑色)。但是,合法 操作必须满…

Grafana+Loki+Promtail 日志监控

目录前置工作用户组(按需创建)GrafanaLokiLoki 配置文件Promtail配置文件配置数据源创建仪表盘添加查询项 前置工作Centos 7 关闭防火墙 (systemctl stop firewalld) 独立的用户组(可以不创建)用户组(按需创建) # 创建用户组 groupadd grafana # 新建一个家目录为`/home/graf…