BZOJ 3473: 字符串 (广义后缀自动机)

/*
广义后缀自动机, 每次加入维护 该right集合的set, 然后可以更新所有的parent,最终能够出现在k个串中right集合也就是set大小大于等于k的部分
这样的话就给了我们要跳的节点加了一个限制, 也就是跳的时候调到第一个sz>= k的节点, 因为更长的话答案不会增加
数据范围非常迷 

好吧 暴力合并set复杂度过高 
暴力更新祖先的情况竟然会少一个log 

*/

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<set>
#include<string> 
#include<iostream>
#define ll long long 
#define mmp make_pair
#define M 400020
using namespace std;
int read()
{
    int nm = 0, f = 1;
    char c = getchar();
    for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
    return nm * f;
}
int lst = 1, cnt = 1, fa[M], len[M], ch[M][26], tim[M], a[M], n, k;
ll f[M], cor[M], g[M];
//set<int> st[M];
string s[M];
//vector<int> to[M]; 
void insert(int c)
{
    int p = ++cnt, f = lst;
    lst = p;
    len[p] = len[f] + 1;
    while(f && !ch[f][c]) ch[f][c] = p, f = fa[f];
    if(!f) fa[p] = 1;
    else
    {
        int q = ch[f][c];
        if(len[q] == len[f] + 1) fa[p] = q;
        else
        { 
            int nq = ++cnt;
            memcpy(ch[nq], ch[q], sizeof(ch[nq]));
            fa[nq] = fa[q];
            len[nq] = len[f] + 1;
            fa[p] = fa[q] = nq;
            while(f && ch[f][c] == q) ch[f][c] = nq, f = fa[f];
        }
    }
}

//void dfs(int now)
//{
//  for(int i = 0; i < to[now].size(); i++)
//  {
//      int vj = to[now][i];
//      dfs(vj);
//      for(set<int>::iterator it = st[vj].begin(); it != st[vj].end(); it++)
//      {
//          st[now].insert(*it);
//      }
//  }
//  f[now] = st[now].size();
//}

int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> k;
    for(int i = 1; i <= n; i++)
    {
        cin >> s[i];
        lst = 1;
        int l = s[i].length();
        for(int j = 0; j < l; j++)
        {
            insert(s[i][j] - 'a');
        }
    }
    for(int i = 1; i <= n; i++)
    {
        int now = 1;
        for(int j = 0; j < s[i].length(); j++)
        {
            int c = s[i][j] - 'a';
            now = ch[now][c];
            int p = now;
            for(; p && cor[p] != i; p = fa[p]) g[p]++, cor[p] = i;
        }
    }
    for(int i = 1; i <= cnt; i++) tim[len[i]]++;
    for(int i = 1; i <= cnt; i++) tim[i] += tim[i - 1];
    for(int i = 1; i <= cnt; i++) a[tim[len[i]]--] = i;
//  for(int i = cnt; i >= 1; i--)
//  {
//      f[a[i]] = st[a[i]].size();
//      for(set<int>::iterator it = st[a[i]].begin(); it != st[a[i]].end(); ++it)
//      {
//          st[fa[a[i]]].insert(*it);
//      }
//  }
//  for(int i = 2; i <= cnt; i++) to[fa[i]].push_back(i);
//  dfs(1); 
    g[1] = 0;
    for(int i = 1; i <= cnt; i++)
    {
        int now = a[i];
        f[now] = f[fa[now]];
        if(g[now] >= k) f[now] += len[now] - len[fa[now]];
    }
    if(k > n)
    {
        for(int i = 1; i <= n; i++) cout << "0 ";
    }
    else
    {
        ll ans;
        for(int i = 1; i <= n; i++)
        {
            ans = 0;
            int now = 1, l = s[i].length();
            for(int j = 0; j < l; j++)
            {
                int c = s[i][j] - 'a';
                now = ch[now][c];
                ans += f[now];
            }
            cout << ans << " ";
        }
    }
    return 0;
}


/*

3 3

abcdfdsadaseeeeeeeeefffffffffffffffffffffffffffffffffffffffffffeeeeeeee

affsfdsdfewfeeeeeeffffffffeeeeeeeee

abasdsadwdsadsadwdasdadafsafs

*/

转载于:https://www.cnblogs.com/luoyibujue/p/10630135.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值