51nod 1600 Simple KMP【后缀自动机+LCT】【思维好题】*

Description

对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i)
显然对于一个字符串,如果我们将每个0<=i<=|S|看成一个结点,除了i=0以外i向fail[i]连边,这是一颗树的形状,根是0
我们定义这棵树是G(S),设f(S)是G(S)中除了0号点以外所有点的深度之和,其中0号点的深度为-1
定义key(S)等于S的所有非空子串S'的f(S')之和
给定一个字符串S,现在你要实现以下几种操作:
1.在S最后面加一个字符
2.询问key(S)
善良的出题人不希望你的答案比long long大,所以你需要将答案对1e9+7取模

Input

第一行一个正整数Q
Q<=10^5
第二行一个长度为Q的字符串S

Output

输出Q行,第i行表示前i个字符组成的字符串的答案

Input示例

5
abaab

Output示例

0
0
1
4
9


思路

这题真的好,我用了一个晚上+一个下午才想明白+做出来

然后说思路
首先发现一下性质
考虑分解一个串S的(f(S))的贡献
为了解决这个问题我们考虑分解每一个前缀的贡献
那么前缀子串S的贡献怎么统计?

  • 性质1:对于任意一个前缀,它的贡献是除了本身这个子串在S中出现的次数
    • 证明:
      对于一个前缀位置x和一个匹配位置p,
      (G(S))上x一定是p的祖先,因此带来出现次数的贡献

所以就可以把(f(S))分解成每个前缀的出现次数了
那么(key(S)=sum_{S'是S的非空子串}f(S'))怎么计算呢?
这所有的子串可以拆分成若干多个前缀
所以考虑计算每个子串对(key(s))的贡献,设这个子串的结束位置是(endpos(S')),那么就会对(len(S)-endpos(S')+1)个非空子串产生贡献
这个贡献并不好统计
又因为这道题需要计算每一次的增量,反而让我们的计算变得简单了
因为新增的串只是后缀

  • 性质2:每一次答案增量是上一次的kay(len-1)+新增的后缀在原串中的出现次数
    • 证明:
      上一次的key(len-1)很好理解啊
      因为对于之前的每个子串,产生贡献的子串又多了一个
      也就是变成了相对于原来的(len(S)+1-endpos(S')+1),所以加上(key(len-1))
      然后为什么又新增的后缀在原串中的出现次数呢?
      是因为每次要考虑如果对于一个子串在后面多出现了一次,贡献就需要++
      所以新增的贡献就是除开新增后缀之外的所有后缀出现次数

然后考虑用LCT动态维护在parent树上的链接关系
同时维护right和答案
至于这个答案怎么维护
因为后缀自动机每个节点表示了一个或多个串,所以在统计的时候需要乘上(t->maxl - t->prt->maxl)的贡献,这样就可以统计所有贡献
每一次进行扩展的时候可以维护关系,然后扩展结束之后当前节点就表示最后一个点(可以接收整个字符串)
然后只需要把从这个节点到root的parent树提取出来,先计算答案然后累加贡献就好了


真的是好题
墙裂推荐


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define for_up(a, b, c) for (int a = b; a <= c; ++a)
#define for_down(a, b, c) for (int a = b; a >= c; --a)
#define for_vector(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x){
  bool w = 1;x = 0;
  char c = getchar();
  while(!isdigit(c) && c != '-')c = getchar();
  if(c == '-')w = 0, c = getchar();
  while(isdigit(c)) {
    x = (x<<1) + (x<<3) + c -'0';
    c = getchar();
  }
  if(!w)x=-x;
}
template <typename T>
void Write(T x){
  if(x < 0) {
    putchar('-');
    x=-x; 
  }
  if(x > 9)Write(x / 10);
  putchar(x % 10 + '0');
}
//----------------------------------------------
const int Mod = 1e9 + 7;
const int N = 1e5 + 10;
const int CHARSET_SIZE = 26;
int add(int a, int b) {
  a += b;
  if(a >= Mod) a -= Mod;
  return a;
}
int mul(int a, int b) {
  return 1ll * a * b %Mod;
}
namespace LCT {
struct Splay {
  Splay *ch[2], *fa;
  int val, len, sum_len, right;
  int tag; //add tag of siz of right
  //val euqal to sum (len * right)
  Splay():val(0), len(0), sum_len(0), right(0), tag(0){}
}_null,*null=&_null;
Splay *newnode() {
  Splay *t=new Splay();
  t->fa = t->ch[0] = t->ch[1] = null;
  return t;
}
bool isroot(Splay *t) {
  return t->fa->ch[0] != t && t->fa->ch[1] != t;
}
bool Son(Splay *t) {
  return t->fa->ch[1] == t;
}
void pushnow(Splay *t, int vl){
  t->tag = add(t->tag, vl);
  t->right = add(t->right, vl);
  t->val = add(t->val, mul(vl, t->sum_len));
}
void pushup(Splay *t) {
  t->sum_len = t->len;
  t->val = mul(t->sum_len, t->right);
  if (t->ch[0] != null) {
    t->sum_len = add(t->sum_len, t->ch[0]->sum_len);
    t->val = add(t->val, t->ch[0]->val);
  }
  if (t->ch[1] != null) {
    t->sum_len = add(t->sum_len, t->ch[1]->sum_len);
    t->val = add(t->val, t->ch[1]->val);
  }
}
void pushdown(Splay *t) {
  if(!isroot(t))pushdown(t->fa);
  if (!t->tag) return;
  if (t->ch[0] != null) pushnow(t->ch[0], t->tag);
  if (t->ch[1] != null) pushnow(t->ch[1], t->tag);
  t->tag = 0;
}
void rotate(Splay *t) {
  Splay *f = t->fa, *g = f->fa;
  bool a = Son(t),b = a ^ 1;
  if (!isroot(f)) g->ch[Son(f)] = t;
  t->fa = g;
  f->ch[a] = t->ch[b];
  t->ch[b]->fa = f;
  t->ch[b] = f;
  f->fa = t;
  pushup(f);
  pushup(t);
}
void splay(Splay *t) {
  pushdown(t);
  while (!isroot(t)) {
    Splay *f = t->fa;
    if (!isroot(f)) {
      if (Son(t)^Son(f)) rotate(t);
      else rotate(f);
    }
    rotate(t);
  }
}
void access(Splay *t) {
  Splay *tmp = null;
  while (t != null) {
    splay(t);
    t->ch[1] = tmp;
    pushup(t);
    tmp = t;t = t->fa;
  }
}
//makeroot function in sam doesn't need rev
void makeroot(Splay *x) {
  access(x);
  splay(x);
}
void cut(Splay *x, Splay *y) {
  makeroot(x);
  splay(y);
  y->ch[1] = null;
  x->fa = null;
  pushup(y);
}
void link(Splay *x, Splay *y) {
  makeroot(y);
  x->fa = y;
}
};
using namespace LCT;
namespace Suffix_Automaton {
struct Sam {
  Sam *ch[CHARSET_SIZE], *prt;
  int maxl, right;
  Splay *splay; 
  Sam(int maxl = 0, int right = 0):ch(), prt(NULL), maxl(maxl), right(right) {
    splay = newnode();
  }
}*root, *last;
void init() {
  last = root = new Sam;
}
void modify(Sam *t) {
  t->splay->len = t->maxl - t->prt->maxl;
  t->splay->right = t->right;
  pushup(t->splay);
}
int extend(int c) {
  Sam *u = new Sam(last->maxl + 1, 1), *v = last;
  for (;v && !v->ch[c]; v = v->prt) v->ch[c] = u;
  if(!v){
    u->prt = root;
    modify(u);
    link(u->splay, root->splay);
  }else if(v->maxl + 1 == v->ch[c]->maxl){
    u->prt = v->ch[c];
    modify(u);
    link(u->splay, v->ch[c]->splay);
  }else{
    Sam *n = new Sam(v->maxl + 1, 0),*o = v->ch[c];
    copy(o->ch, o->ch + CHARSET_SIZE, n->ch);
    n->prt = o->prt;
    makeroot(o->splay);
    n->right = o->right = o->splay->right;
    modify(n);
    link(n->splay, o->prt->splay);
    cut(o->splay, o->prt->splay);
    o->prt = u->prt = n;
    modify(o);
    modify(u);
    link(o->splay, n->splay);
    link(u->splay, n->splay);
    for(;v && v->ch[c] == o; v = v->prt) v->ch[c] = n;
  }
  last = u;
  makeroot(u->splay);
  Splay *now = u->splay->ch[0];
  int res = now->val;
  pushnow(now, 1);
  return res;
}
};
using namespace Suffix_Automaton;
int f[N],n;
char c[N];
int main() {
  freopen("input.txt", "r", stdin);
  Read(n);
  scanf("%s",c+1);
  Suffix_Automaton::init();
  for_up(i, 1, n)
    f[i] = add(f[i-1], extend(c[i]-'a'));
  for_up(i, 1, n) {
    f[i] = add(f[i], f[i-1]);
    Write(f[i]);
    putchar('
');
  }
  return 0;
}
原文地址:https://www.cnblogs.com/dream-maker-yk/p/9720627.html