http://hihocoder.com/problemset/problem/1413?sid=1199641

这题断断续续做了2个多星期吧,一直不会

设总答案为sum,替换后新加的子串数量为x,失去的是y,那么每个位置的答案就是sum + x[i] - y[i]

首先可以知道如果把某个位置设置成'#',那么肯定有i * (len - i + 1)个新的不同的子串

比如是aa#cb,左边有i个选择,右边有len - i + 1个选择,根据组合数学就是i * (len - i + 1)个不同的子串

然后替换过后,就会有一些原本有的子串被删除了。

对于每一个状态,可以拓扑出它的mxpos和mipos也就是endpos的两个位置。

那么对于一个长度是len的子串,是否删除 了这个字符后 在整个字符串中不再出现,可以这样判断

如果mxpos - len + 1(也就是这个长度是len的子串的最大开始位置),如果这个位置还 < mipos那么如果删除了这个位置

肯定会丢失这个长度是len的字符串了。可以画个图吧看看

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 3e5 + 20, N = 26;
struct SAM {int mxCnt[maxn << 1], son[maxn << 1][N], fa[maxn << 1], pos[maxn << 1];int flag[maxn << 1][3]; //是否前缀节点int mi[maxn << 1], mx[maxn << 1];int root, last, DFN, t;int create() {++t;mxCnt[t] = pos[t] = fa[t] = NULL;
//        mi[t] = inf, mx[t] = -inf;for (int i = 0; i < 3; ++i) flag[t][i] = NULL;for (int i = 0; i < N; ++i) son[t][i] = NULL;return t;}void init() {++DFN;t = 0, root = 1;last = create();}void addChar(int x, int _pos, int id) { // _pos表示在原串中的位置int p = last;int np = create();last = np;mxCnt[np] = mxCnt[p] + 1, pos[np] = _pos, flag[np][id] = DFN; //前缀节点for (; p && son[p][x] == NULL; p = fa[p]) son[p][x] = np;if (p == NULL) {fa[np] = root;return;}int q = son[p][x];if (mxCnt[q] == mxCnt[p] + 1) {fa[np] = q;return;}int nq = create(); //用来代替q的,默认不是前缀节点flag[nq][id] = DFN - 1; //默认不是前缀节点pos[nq] = pos[q]; //pos要和q相同for (int i = 0; i < N; ++i) son[nq][i] = son[q][i];fa[nq] = fa[q], mxCnt[nq] = mxCnt[p] + 1;fa[q] = nq, fa[np] = nq;for (; p && son[p][x] == q; p = fa[p]) son[p][x] = nq;}int dp[maxn << 1], in[maxn << 1], que[maxn << 1];void topo() { //多次使用不用清空for (int i = 2; i <= t; ++i) {in[fa[i]]++;mi[i] = mx[i] = pos[i];}int head = 0, tail = 0;for (int i = 2; i <= t; ++i) {if (in[i] == 0) que[tail++] = i;}while (head < tail) {int cur = que[head++];if (cur == root) break;mx[fa[cur]] = max(mx[fa[cur]], mx[cur]);in[fa[cur]]--;if (in[fa[cur]] == 0) que[tail++] = fa[cur];}}
} sam;
LL cnt[maxn], sub[maxn];
void add(int be, int en, LL val, LL d) {cnt[be] += val;cnt[en + 1] -= d * (en - be) + val;sub[be + 1] += d;sub[en + 1] -= d;
}
void init(int en) {for (int i = 1; i <= en; ++i) {sub[i] += sub[i - 1];cnt[i] += cnt[i - 1] + sub[i];}
}char str[maxn];void work() {int len;cin >> len;sam.init();scanf("%s", str + 1);LL ans = 0;for (int i = 1; str[i]; ++i) {sam.addChar(str[i] - 'a', i, 0);}sam.topo();
//    int fuck = 5;
//    printf("%d\n", sam.mx[fuck + 1]);for (int i = 2; i <= sam.t; ++i) {ans += sam.mxCnt[i] - sam.mxCnt[sam.fa[i]];if (sam.mx[i] - sam.mxCnt[i] + 1 <= sam.mi[i]) {int be = sam.mx[i] - sam.mxCnt[i] + 1;int en = min(sam.mx[i] - sam.mxCnt[sam.fa[i]], sam.mi[i]);int len = en - be + 1;
//            printf("%d %d\n", be, en);add(be, en, 1, 1);be = en + 1;en = sam.mi[i];  //还有一段,要全部加上len个
//            printf("%d %d\n\n", be, en);if (be <= en) add(be, en, len, 0);}}init(len);
//    printf("%d\n", cnt[4]);for (int i = 1; i <= len; ++i) {printf("%lld ", ans + 1LL * (i) * (len - i + 1) - cnt[i]);}}int main() {
#ifdef localfreopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endifwork();return 0;
}

View Code

转载于:https://www.cnblogs.com/liuweimingcprogram/p/7610130.html

#1413 : Rikka with String 后缀自动机 + 二级差分相关推荐

  1. hdu 6086 Rikka with String(AC自动机+状压dp)

    题目链接:hdu 6086 Rikka with String 题意: 给你n个只含01的串,和一个长度L,现在让你构造出满足s[i]≠s[|s|−i+1] for all i∈[1,|s|] ,长度 ...

  2. hdu 6194string string string 后缀自动机

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6194 查询原串中出现次数等于k次的子串数量.需要用到基数排序. 构造完后缀自动机之后将节点按照maxl ...

  3. hdu 6086 -- Rikka with String(AC自动机 + 状压DP)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

  4. 2019牛客暑期多校训练营(第四场)I - String (后缀自动机+回文树)

    题目链接 题意 给一个字符串,求字符串子串的最大集合,集合中字符串互不相等,相等的定义为:a≠ba =\not ba≠​b 而且 a≠rev(b)a =\not rev(b)a≠​rev(b) ...

  5. 牛客多校4 - Count New String(序列自动机+广义后缀自动机)

    题目链接:点击查看 题目大意: 题目分析:首先观察到集集合 A 中那个套娃的表示,外层的范围是 [ x1 , y1 ] ,内层是 [ x2 , y2 ] ,而内层的定义域实际上是包含在外层的定义域内的 ...

  6. 后缀自动机 ---- P3804 【模板】后缀自动机(求每个等价类最长串的出现次数)

    后缀自动机一些关键点 首先后缀自动机上面每个节点都是一个等价类并且是最长的字符串的结尾 后缀自动机上的fail链反建就是parent tree,下面是SAM和Parent tree的构造 对于这道模板 ...

  7. BZOJ5137lg4081(广义后缀自动机,set启发式合并)

    BZOJ5137&&lg4081(广义后缀自动机,set启发式合并) 题面 自己找去 HINT 给定多个文本串,让你查询每个文本串中有多少个本质不同的子串且这个子串只出现在当前这个文本 ...

  8. UOJ #131 BZOJ 4199 luogu P2178【NOI2015】品酒大会 (后缀自动机、树形DP)

    UOJ #131 BZOJ 4199 luogu P2178[NOI2015]品酒大会 (后缀自动机.树形DP) 水是水,但是写出了不少问题,因此写一发博客. https://www.luogu.or ...

  9. hihoCoder #1445 : 后缀自动机二·重复旋律5

    描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中出现了多少不同的旋律? 输入 共一行,包含一个由小写字母构成的字符串.字符串长度不 ...

最新文章

  1. elasticsearch 后置过滤器(Post Filter)
  2. vue中的v-model原理,与组件自定义v-model
  3. Kotlin中的接口回调
  4. Python基础(8)_迭代器、生成器、列表解析
  5. linux纯内核直接用吗,Linux:为啥内核有的变量没有初始化就敢直接使用?
  6. superset mysql数据源配置_superset 性能优化1-已经使用中的superset更改默认数据源sqlite到mysql...
  7. 吴钩:打开宋代的“隐藏玩法”
  8. 我爆一个托 QQ305242038 电话 18782169971
  9. python大数据在汽车销售中的数据分析与研究
  10. CAD常用字体库大全
  11. 十三届蓝桥杯EDA省赛赛后感
  12. beta函数与置信度估计
  13. 圆的半径java_计算圆的半径
  14. 已解决org.springframework.beans.factory.UnsatisfiedDependencyException异常的正确解决方法,亲测有效!!!
  15. 程序人生:如果纯做业务测试的话,在测试行业有出路吗?
  16. html登录号如何显示用户名,HTML更改登录标签,登录后用户名
  17. 【设计模式十六之装饰模式】装饰者模式
  18. 【每天一个没用的干货】海康摄像头rtsp流 不登录即播放
  19. 用 API 作简繁体转换
  20. 光是无限远服务器怎么登陆,sv独立客户端怎么连接服务器(sv独立客户端登录密码)...

热门文章

  1. Linux之文件查找
  2. B. super_log(2019ICPC区域网络赛南京站)
  3. import pymysql 没有模块_小白详细的 python 模块的运用
  4. mysql冷备增量备份,MySQL备份与恢复之真实环境使用冷备(2)
  5. HCIA-Datacom新版数通认证都考什么内容?
  6. Linux入门基础思维导图
  7. 迁移 Express 到函数计算
  8. java hook 框架_hook框架-frida简单使用模板以及frida相关接口
  9. sql-server基础三(select 、update、insert,delete)
  10. mysql查询总结_mysql查询总结相关