当前位置: 首页 > wzjs >正文

官方网站英语域名注册哪个网站好

官方网站英语,域名注册哪个网站好,在线网站客服系统,郑州软件公司排名T1 放 CF *3400。。。。 虽然有一点点加强但是做法相同,按照这道题的题意来讲。 题意 给定 m m m 个模式串 t i t_i ti​,每个模式串有一个价值 v i v_i vi​。 同时给定一个长度为 n n n 的模板串 S S S。 q q q 次询问,每次询问给定…

T1 放 CF *3400。。。。
虽然有一点点加强但是做法相同,按照这道题的题意来讲。

题意

给定 m m m 个模式串 t i t_i ti,每个模式串有一个价值 v i v_i vi
同时给定一个长度为 n n n 的模板串 S S S q q q 次询问,每次询问给定 l , r l, r l,r,你需要求出 S l , r S_{l, r} Sl,r 中每个模式串的出现次数乘价值之和: ∑ i ( c n t i × v i ) \sum\limits_{i}(cnt_i \times v_i) i(cnti×vi)
强制在线。

1 ≤ n , m , q ≤ 10 6 1 \leq n, m, q \leq 10^6 1n,m,q106 ∑ ∣ t i ∣ ≤ 10 6 \sum|t_i| \leq 10^6 ti106

分析

首先看到多模式串匹配所以我们来考虑 A C A M ACAM ACAM。( A C AC AC 自动机)

不要因为学过 S A M SAM SAM 就只要看到字符串题就往 S A M SAM SAM 上想, S A M SAM SAM 在处理一个或多个字符串的子串信息时比较有优势,但是相对的它的结构更复杂或许拓展起来就比较难。像这道题所求信息只是简单的多模式串匹配,因此我们考虑 A C AC AC 自动机。

我们建出 t i t_i ti A C AC AC 自动机。将 S S S A C AC AC 自动机上匹配一遍,能求出以 S S S 的每个位置为结尾所有匹配的字符串的价值之和,记为 h i h_i hi。那么将 h i h_i hi 求前缀和得到 h i ′ h'_i hi,每次询问回答 h r ′ − h l − 1 ′ h'_r - h'_{l - 1} hrhl1

发现这个做法虽然很自然但是却并不正确,因为有可能一个 h i h_i hi 中包含了一个左端点不在 [ l , r ] [l, r] [l,r] 以内的字符串的贡献。我们尝试在这个做法上进行一些修改使它正确。

假设以位置 i i i 为结尾能匹配的最长模式串的编号为 g i g_i gi,我们找到 [ l , r ] [l, r] [l,r] 中最靠后的位置 p p p,满足 p − ∣ t g p ∣ + 1 ≤ l p - |t_{g_p}| + 1 \leq l ptgp+1l,那么对于 [ p + 1 , r ] [p + 1, r] [p+1,r],它们的贡献就等于 h r − h p h_r - h_p hrhp

对于 [ l , p ] [l, p] [l,p] 的贡献怎么算呢?
暴力的想法是我们对 S l , p S_{l, p} Sl,p A C AC AC 自动机上跑一遍匹配,过程中求出贡献,这显然复杂度不可接受。
但是注意到 S l , p S_{l, p} Sl,p 完全等于 t g p t_{g_p} tgp 长为 p − l + 1 p - l + 1 pl+1 的后缀,我们完全可以预处理所有 t i t_i ti 的后缀信息,这样就可以 O ( 1 ) O(1) O(1) 查询。

预处理所有 t i t_i ti 的后缀信息:将所有 t i t_i ti 的反串建 A C A M ACAM ACAM,然后对每个 t i t_i ti 从后往前跑一遍匹配即可。复杂度 O ( ∑ ∣ t i ∣ ) O(\sum |t_i|) O(ti)

每次询问用线段树二分找 p p p,复杂度 O ( m log ⁡ n ) O(m \log n) O(mlogn)

总复杂度 O ( ∑ ∣ t i ∣ + m log ⁡ n ) O(\sum |t_i| + m\log n) O(ti+mlogn)。代码很好写。

CODE:

// 把要求的东西拆成两部分,一部分可以直接算,另一部分可以转化到一个可以预处理的问题上 
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
char s[N], t[N];
int n, m, q, l[N], r[N], g[N]; // g[i] 表示 i 位置为结尾能匹配的最长 t 串的编号 
LL v[N], S[N], sum[N];
struct ACAM { int tr[N][26], fail[N], et[N], tot; // 初始节点从 0 开始 LL val[N];inline void ins(char *s, int idx, LL v) {int p = 0, len = strlen(s + 1);for(int i = 1; i <= len; i ++ ) {if(!tr[p][s[i] - 'a']) tr[p][s[i] - 'a'] = ++ tot;p = tr[p][s[i] - 'a'];}val[p] += v; et[p] = idx;}inline int Max(int x, int y) {if(!x || !y) return x ^ y;else return r[x] - l[x] <= r[y] - l[y] ? y : x;}inline void build() {queue< int > q;for(int i = 0; i < 26; i ++ ) if(tr[0][i]) q.push(tr[0][i]);while(!q.empty()) {int u = q.front(); q.pop();for(int i = 0; i < 26; i ++ ) {if(tr[u][i]) {fail[tr[u][i]] = tr[fail[u]][i];val[tr[u][i]] += val[fail[tr[u][i]]];et[tr[u][i]] = Max(et[tr[u][i]], et[fail[tr[u][i]]]);q.push(tr[u][i]);}else tr[u][i] = tr[fail[u]][i];}}}
} AC[2]; // 正反 
struct SegmentTree {int l, r, mn;#define l(x) tree[x].l#define r(x) tree[x].r#define mn(x) tree[x].mn
} tree[N * 4];
inline void update(int p) {mn(p) = min(mn(p << 1), mn(p << 1 | 1));}
void build(int p, int lp, int rp) {l(p) = lp, r(p) = rp;if(lp == rp) {mn(p) = lp - (r[g[lp]] - l[g[lp]] + 1) + 1;return ;}int mid = (lp + rp >> 1);build(p << 1, lp, mid);build(p << 1 | 1, mid + 1, rp);update(p);
}
int ask(int p, int l, int r, int lim) {if(l <= l(p) && r >= r(p)) {if(mn(p) > lim) return lim - 1;else {if(l(p) == r(p)) return l(p);if(mn(p << 1 | 1) <= lim) return ask(p << 1 | 1, l, r, lim);else return ask(p << 1, l, r, lim);}}int mid = (l(p) + r(p) >> 1);if(r <= mid) return ask(p << 1, l, r, lim);else if(l > mid) return ask(p << 1 | 1, l, r, lim);else {int ret = ask(p << 1 | 1, l, r, lim);if(ret != lim - 1) return ret;else return ask(p << 1, l, r, lim);}
}
int main() {	scanf("%s", s + 1); n = strlen(s + 1);scanf("%d", &m); int st = 0;for(int i = 1; i <= m; i ++ ) {char tmp[N]; scanf("%s", tmp + 1); int len = strlen(tmp + 1);for(int j = 1; j <= len; j ++ ) t[st + j] = tmp[j];l[i] = st + 1, r[i] = st + len;st += len; scanf("%lld", &v[i]);AC[0].ins(tmp, i, v[i]); reverse(tmp + 1, tmp + len + 1);AC[1].ins(tmp, i, v[i]);}AC[0].build(); AC[1].build();for(int i = 1; i <= m; i ++ ) {int p = 0;for(int j = r[i]; j >= l[i]; j -- ) {p = AC[1].tr[p][t[j] - 'a'];S[j] = AC[1].val[p];}}for(int i = 1; i <= st; i ++ ) S[i] += S[i - 1];int p = 0;for(int i = 1; i <= n; i ++ ) {p = AC[0].tr[p][s[i] - 'a'];sum[i] = AC[0].val[p]; g[i] = AC[0].et[p];}for(int i = 1; i <= n; i ++ ) sum[i] += sum[i - 1];LL lstans = 0;build(1, 1, n);scanf("%d", &q);while(q -- ) {LL L, R; scanf("%lld%lld", &L, &R);L = (L ^ lstans) % n + 1, R = (R ^ lstans) % n + 1;if(L > R) swap(L, R); lstans = 0;int p = ask(1, L, R, L); // 找到 mn <= L 的最靠后的位置, 没有返回 L - 1lstans += sum[R] - sum[p]; if(p != L - 1) {int x = g[p]; // 那么就是 x 的一段长为 p - L + 1 的后缀 lstans += S[r[x]] - S[r[x] - (p - L + 1)];}printf("%lld\n", lstans);}return 0;
}

总结

本题中做法的核心相当于我们减少了所要维护的信息。
第二部分的暴力思路其实等价于求出所有子串匹配的信息,维护所有子串的信息显然是不可接受的,但是我们通过转化将它变成了模式串的后缀信息,这样就是可接受的。
或许与字符串某些放缩的思路类似???
总之如果遇到所有维护的子串信息过多,我们就尝试能不能转化成前后缀信息,因为前后缀的数量是比较少的。

http://www.dtcms.com/wzjs/167122.html

相关文章:

  • 建设学校网站策划书关键词seo公司推荐
  • 绵阳 网站 建设私人浏览器
  • 做下载网站好不好做如何让百度搜索排名靠前
  • 专业网站建设出售矿泉水软文广告500字
  • web网站服务器的建设磁力狗在线引擎
  • 不同的网站前缀就是不同的域名吗浏览器2345网址导航下载安装
  • 新手去哪个网站做翻译名片seo什么意思
  • 西宁企业网站开发定制免费无代码开发平台
  • 大型网站建站公司福州短视频seo
  • 网站建设与运营推广的回报材料深圳外贸网站推广
  • 南宁网站建设seo百度竞价排名公式
  • 全国旅游大型网站建设萝卜建站
  • vr网站建设nba交易最新消息汇总
  • 省市网站建设考核标准要求网站seo设计方案案例
  • vue网站开发深圳seo关键词优化
  • 建设网站费用多少正规专业短期培训学校
  • 凡科的模板做网站谷歌官网入口
  • 大网站是用什么做html5的营销方式有哪些
  • 怎么做网站服务器百度下载安装免费
  • 做调查挣钱的网站网站客服系统
  • 宁夏吴忠市红寺堡建设局网站win优化大师有免费版吗
  • 网站建设基本流程流程图掉发脱发严重是什么原因
  • 模板网站与定制网站的区别宁波seo外包哪个品牌好
  • 网站备案时间太长教育培训班
  • 普通企业网站营销电商平台如何推广运营
  • 网站搭建系统百度手机助手app下载安装
  • 潍坊优化网站新开传奇网站
  • 大望路网站制作营销计划书7个步骤
  • 一个网站是如何知道是谁来访问网络推广哪个平台最好
  • 香橼做空机构网站网页制作模板