这题TM是计数神题......SAM就是个板子,别脑残写错就完事了。有个技巧是快速定位子串,倍增即可。

考虑反着来,就是两个断点切割所有串,求方案数。

大概分类讨论一下......先特判掉一些情况。然后考虑最左右的两个串是否相交。

相交的情况比较友善,先特殊统计有断点在交集中。之后枚举第一个断点切割了1 ~ i个串。第二个断点就切割i+1 ~ m个串。

然后写出一个∑的式子,拆开之后发现维护right集合平方和和right集合相邻元素的乘积即可。

不相交的麻烦点(极其麻烦...)考虑枚举第一个断点切割了1~i个串,这里的i的限制是L ~ R,可以先求出来。

然后继续化简一个∑式子,最后发现要维护的东西差不多。于是这题做完了。

感想:对拍真好用.jpg

 #include <bits/stdc++.h>

 typedef long long LL;
const int N = , M = ; struct Edge {
int nex, v;
}edge[N]; int tp; int tr[N][], fail[N], len[N], rt[N], last = , tot = ;
int ls[M], rs[M], cnt, e[N], ed[N], fa[N][], pw[N];
LL sum0[M], sum2[M], sumd[M], large[M], small[M];
int n, q;
char str[N]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} inline void pushup(int o) {
if(!ls[o] && !rs[o]) return;
sum0[o] = sum0[ls[o]] + sum0[rs[o]];
sum2[o] = sum2[ls[o]] + sum2[rs[o]];
sumd[o] = sumd[ls[o]] + sumd[rs[o]];
if(ls[o] && rs[o]) sumd[o] += small[rs[o]] * large[ls[o]];
large[o] = std::max(large[ls[o]], large[rs[o]]);
small[o] = std::min(small[ls[o]], small[rs[o]]);
return;
} int merge(int x, int y) {
if(!x || !y) return x | y;
int o = ++cnt;
large[o] = large[x];
small[o] = small[x];
sum0[o] = sum0[x];
sum2[o] = sum2[x];
sumd[o] = sumd[x];
ls[o] = merge(ls[x], ls[y]);
rs[o] = merge(rs[x] ,rs[y]);
pushup(o);
return o;
} void insert(int p, int l, int r, int &o) {
if(!o) o = ++cnt;
if(l == r) {
large[o] = small[o] = r;
sum0[o] = ;
sum2[o] = 1ll * r * r;
sumd[o] = ;
return;
}
int mid = (l + r) >> ;
if(p <= mid) insert(p, l, mid, ls[o]);
else insert(p, mid + , r, rs[o]);
pushup(o);
return;
} inline void insert(char c, int id) {
int f = c - '', p = last, np = ++tot;
last = np;
insert(id, , n, rt[np]);
len[np] = len[p] + ;
while(p && !tr[p][f]) {
tr[p][f] = np;
p = fail[p];
}
if(!p) {
fail[np] = ;
}
else {
int Q = tr[p][f];
if(len[Q] == len[p] + ) {
fail[np] = Q;
}
else {
int nQ = ++tot;
len[nQ] = len[p] + ;
fail[nQ] = fail[Q];
fail[Q] = fail[np] = nQ;
memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
while(tr[p][f] == Q) {
tr[p][f] = nQ;
p = fail[p];
}
}
}
return;
} int ask0(int L, int R, int l, int r, int o) {
if(!o) return ;
if(L <= l && r <= R) return sum0[o];
int mid = (l + r) >> , ans = ;
if(L <= mid) ans += ask0(L, R, l, mid, ls[o]);
if(mid < R) ans += ask0(L, R, mid + , r, rs[o]);
return ans;
} LL ask2(int L, int R, int l, int r, int o) {
if(!o) return ;
if(L <= l && r <= R) return sum2[o];
int mid = (l + r) >> ;
LL ans = ;
if(L <= mid) ans += ask2(L, R, l, mid, ls[o]);
if(mid < R) ans += ask2(L, R, mid + , r, rs[o]);
return ans;
} LL askd(int L, int R, int l, int r, int o) {
if(!o) return ;
if(L <= l && r <= R) return sumd[o];
int mid = (l + r) >> ;
if(R <= mid) return askd(L, R, l, mid, ls[o]);
if(mid < L) return askd(L, R, mid + , r, rs[o]);
LL ans = askd(L, R, l, mid, ls[o]) + askd(L, R, mid + , r, rs[o]);
if(ls[o] && rs[o]) {
ans += large[ls[o]] * small[rs[o]];
}
return ans;
} int getKpos(int k, int l, int r, int o) {
if(l == r) return r;
int mid = (l + r) >> ;
if(k <= sum0[ls[o]]) return getKpos(k, l, mid, ls[o]);
else return getKpos(k - sum0[ls[o]], mid + , r, rs[o]);
} void DFS(int x) {
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
fa[y][] = x;
DFS(y);
rt[x] = merge(rt[x], rt[y]);
}
return;
} inline void prework() {
for(int i = ; i <= tot; i++) pw[i] = pw[i >> ] + ;
for(int j = ; j <= pw[tot]; j++) {
for(int i = ; i <= tot; i++) {
fa[i][j] = fa[fa[i][j - ]][j - ];
}
}
return;
} inline int getPos(int x, int Len) {
int t = pw[tot];
while(t >= && len[fa[x][]] >= Len) {
if(len[fa[x][t]] >= Len) {
x = fa[x][t];
}
t--;
}
return x;
} inline LL getAns(int Len, int root) { if(Len == ) return ; int r1 = small[root], rn = large[root];
int l1 = r1 - Len + , ln = rn - Len + ; if(ask0(r1 + Len - , ln, , n, root)) {
return ;
}
LL ans = ;
if(r1 > ln) { /// cross
ans = sum2[root] - sumd[root] - 1ll * r1 * rn;
LL temp = (r1 - ln);
ans += (temp - ) * temp / + temp * (n - temp - );
}
else {
int ql = ask0(, r1 + Len - , , n, root), qr = ask0(, ln, , n, root);
int L = qr, R = ql;
int rL = getKpos(L, , n, root), rR = getKpos(R, , n, root), nexr = getKpos(R + , , n, root);
ans = 1ll * (r1 - rR + Len - ) * (nexr - ln) + 1ll * rL * ln - 1ll * rR * ln;
ans += ask2(rL + , rR, , n, root) - askd(rL, rR, , n, root);
}
return ans;
} int main() {
memset(small, 0x3f, sizeof(small));
scanf("%d%d", &n, &q);
scanf("%s", str + );
for(int i = ; i <= n; i++) {
insert(str[i], i);
}
int p = ;
for(int i = ; i <= n; i++) {
int f = str[i] - '';
p = tr[p][f];
ed[i] = p;
//printf("i = %d p = %d \n", i, p);
}
for(int i = ; i <= tot; i++) add(fail[i], i);
DFS();
prework();
LL SUM = 1ll * (n - ) * (n - ) / ;
for(int i = , l, r; i <= q; i++) {
scanf("%d%d", &l, &r);
LL t = getAns(r - l + , rt[getPos(ed[r], r - l + )]);
printf("%lld\n", SUM - t);
}
return ;
}

AC代码

洛谷P4384 制胡窜的更多相关文章

  1. Loj #2479. 「九省联考 2018」制胡窜

    Loj #2479. 「九省联考 2018」制胡窜 题目描述 对于一个字符串 \(S\),我们定义 \(|S|\) 表示 \(S\) 的长度. 接着,我们定义 \(S_i\) 表示 \(S\) 中第 ...

  2. 并不对劲的复健训练-bzoj5253:loj2479:p4384:[2018多省联考]制胡窜

    题目大意 给出一个字符串\(S\),长度为\(n\)(\(n\leq 10^5\)),\(S[l:r]\)表示\(S_l,S_{l+1}...,S_r\)这个子串.有\(m\)(\(m\leq 3\t ...

  3. 洛谷P2429 制杖题 [2017年6月计划 数论10]

    P2429 制杖题 题目描述 求不大于 m 的. 质因数集与给定质数集有交集的自然数之和. 输入输出格式 输入格式: 第一行二个整数 n,m. 第二行 n 个整数,表示质数集内的元素 p[i]. 输出 ...

  4. bzoj5253 [2018多省省队联测]制胡窜

    后缀自动机挺好毒瘤的题. 我们考虑哪些切点是不合法的.肯定是所有的匹配串都被切了. 我们考虑第一个切口的位置. 当第一个切口在第一个出现位置前时,第二个切口必须切掉所有的串. 当第一个切口在$l_{i ...

  5. 【LOJ】#2479. 「九省联考 2018」制胡窜

    题解 老了,国赛之前敲一个后缀树上LCT和线段树都休闲的很 现在后缀树上线段树合并差点把我写死 主要思路就是后缀树+线段树合并+容斥,我相信熟练的OIer看到这已经会了 但就是不想写 但是由于我过于老 ...

  6. 【HEOI 2018】制胡窜

    转载请注明出处:http://www.cnblogs.com/TSHugh/p/8779709.html YJQ的题解把思路介绍得很明白,只不过有些细节说得还是太笼统了(不过正经的题解就应该这个样子吧 ...

  7. [八省联考2018]制胡窜 (SAM+大讨论)

    正着做着实不太好做,正难则反,考虑反着做. 把i,j看成在切割字符串,我们统计有多少对(i,j)会切割所有与\(s_{l,r}\)相同的串.对于在后缀自动机上表示\(s_{l,r}\)的节点x,x的p ...

  8. 洛谷P1017 进制转换

    洛谷P1017 进制转换 题目描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之和的形式.例如:123可表示为 \(1*10 ...

  9. 洛谷 P1017 进制转换

    推荐洛谷 题目描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之和的形式.例如:123可表示为 1*10^2+2*10^1+ ...

随机推荐

  1. MyBatis映射文件2(不支持自增的数据库解决方案/参数处理[单参、多参、命名参数])

    针对Oracle不支持自增的解决方案 Oracle不支持自增,但是它使用序列来模拟自增,每次插入数据的主键是从序列中拿到的值,那么如何获取这个值呢? <insert id="addEm ...

  2. SpringBoot 4.SpringBoot 整合 devtools 实现热部署

    一.添加 devtools 依赖 <!-- Spring boot 热部署 : 此热部署会遇到 java.lang.ClassCastException 异常 --> <!-- op ...

  3. Spring JDBC模版以及三种数据库连接池的使用

    jar包版本有点乱,直接忽略版本号,将就一下. 这里引了aop包是因为在spring3版本之后用模版对数据库库操作时会出现问题,但是不会报错,也没有提示. 所以这里直接引入,以及之后会用到的DBCP与 ...

  4. shell自定义输入输出 read+echo

    自定义格式输入.输出(244)  输出:echo -e 解释转义字符 -n  回车不换行 \n   新的一行,等同于回车 \t 制表符 \r 回车 \b 回退 baskspace 删除键 演示\n \ ...

  5. tomcat 与 nginx,apache的区别

    tomcat 与 nginx,apache的有什么区别 回答一: 题主说的Apache,指的应该是Apache软件基金会下的一个项目——Apache HTTP Server Project:Nginx ...

  6. Fiddler 学习笔记---命令、断点

    输入命令框: 1 输入 ?51testing  高亮显示对应记录 2 >10 选择body大于10的记录 3 <10 选择body<10的记录 4 =200 选择result=200 ...

  7. Python——Flask框架——数据库

    一.数据库框架 Flask-SQLAlchemy (1)安装: pip install flask-sqlalchemy (2)Flask-SQLAlchemy数据库URL 数据库引擎 URL MyS ...

  8. Memcached 分布式集群

    首先解释一下我的标题,用到了 分布式 和 集群两个单词,为什么是集群?解决[相同业务]问题的服务器多个以上就称为集群.这里memcached就是做相同任务的(提供缓存服务)为什么是分布式?虽然针对的是 ...

  9. react 入坑笔记(三) - Props

    React Props props - 参数. 组件类 React.Component 有个 defaultProps 属性,以 class xxx extend React.Component 形式 ...

  10. mesh函数

    [t,W]=meshgrid([2:0.2:7],[0:pi/6:3*pi]); %设置时-频相平面网格点 Gs1=(1/(sqrt(2*pi)*a))*exp(-0.5*abs((t1-t)/a). ...