hihocoder1449 (后缀自动机)

1449 : 后缀自动机三·重复旋律6
时间限制:15000ms
单点时限:3000ms
内存限制:512MB
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。

现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数。但是K不是固定的,小Hi想知道对于所有的K的答案。

输入
共一行,包含一个由小写字母构成的字符串S。字符串长度不超过 1000000。

输出
共Length(S)行,每行一个整数,表示答案。

样例输入
aab
样例输出
2
1
1


求出每个状态的 right r i g h t 集合大小后
一个朴素的做法是对于一个状态中 minx m i n x ~ maxx m a x x 这段长度的 ans a n s 全部更新一遍
这样的做法显然是 O((length|s|)2) O ( ( l e n g t h | s | ) 2 )
我们考虑优化
一个显然的结论是 ans a n s 数组单调递减
所以我们可以对于一次更新只更新 ansmaxx a n s m a x x ,统计答案前令 ansi=max(ansi,ansi+1) a n s i = m a x ( a n s i , a n s i + 1 ) 即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
char s[1001000];
int tr[2001000][26] , par[2001000] , mx[2001000] , cnt , last , R[2001000];
int ans[2001000];
int len;
int read()
{
    int sum = 0;char c = getchar();bool flag = true;
    while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
    while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
    if(flag)  return sum;
     else return -sum;
}  
void extand(int x)
{
    int np = ++cnt , p = last;R[np] = 1;
    mx[np] = mx[p] + 1;last = np;
    while(p && !tr[p][x]) tr[p][x] = np , p = par[p];
    if(!p) par[np] = 1;
    else
    {
        int q = tr[p][x];
        if(mx[q] == mx[p] + 1) par[np] = q;
        else
        {
            int nq = ++cnt;mx[nq] = mx[p] + 1;
            rep(i,0,25) tr[nq][i] = tr[q][i];
            par[nq] = par[q];par[q] = par[np] = nq;
            while(p && tr[p][x] == q) tr[p][x] = nq , p = par[p]; 
        }
    }
    return;
}
int tmp[1001000] , id[2001000];
void topsort()
{
    rep(i,1,cnt) tmp[mx[i]]++;
    rep(i,1,len) tmp[i] += tmp[i-1];
    rep(i,1,cnt) id[tmp[mx[i]]--] = i;
    repp(i,cnt,1) R[par[id[i]]] += R[id[i]];
}
int main()
{
    scanf("%s",s+1);
    len = strlen(s+1);cnt = last = 1;
    rep(i,1,len) extand(s[i]-'a');
    topsort();
    rep(i,1,cnt) ans[mx[i]] = max(ans[mx[i]],R[i]);
    repp(i,len-1,1) ans[i] = max(ans[i],ans[i+1]);
    rep(i,1,len) printf("%d\n",ans[i]); 
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值