「hihocoder1413 Rikka with String」

题目

哈哈哈哈哈哈哈哈哈哈我还没自闭

好像前后调了两天了

哈哈哈哈哈哈哈哈哈哈我还没自闭

这道题就是给定一个小写字母串,回答分别把每个位置上的字符替换为\(#\)后的本质不同的子串数

首先就是跨过这个特殊字符的字符串出现次数显然都是\(1\),这部分的贡献就直接是\(i\times(n-i+1)\)

之后我们用\(SAM\)搞出所有前缀和所有后缀的本质不同子串个数,这时候答案的贡献就是\(pre_{i-1}+beh_{i+1}\)

显然会算多一些在前缀和后缀里都出现的子串

想个办法把这些东西搞出来

我们维护出每个等价类\(endpos\)的最大值\(mx[i]\)和最小值\(mi[i]\)

显然如果特殊字符插入在\([mi[i],mx[i]-len[i]]\)里的话会使得这个字符串在左右两边都被算过

如果特殊字符插入在\([mx[i]-len[i]+1,mx-len[fa[i]]\),发现这里好像需要一个每往后移动一个位置就会少多算一个子串,那就是一个公差为\(-1\)的等差数列啊,二阶差分维护一下就好了

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define LL long long
#define re register
#define maxn 600005
char S[maxn>>1];
struct SAM{
    int len[maxn],fa[maxn],son[maxn][26];
    LL tot;int lst,cnt;
    inline void ins(int c) {
        int p=++cnt,f=lst;lst=p;
        len[p]=len[f]+1;
        while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
        if(!f) {fa[p]=1;tot+=len[p]-len[fa[p]];return;}int x=son[f][c];
        if(len[f]+1==len[x]) {fa[p]=x;tot+=len[p]-len[fa[p]];return;}
        int y=++cnt;tot-=len[x]-len[fa[x]];
        len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
        tot+=len[y]-len[fa[y]],tot+=len[p]-len[fa[p]],tot+=len[x]-len[fa[x]];
        for(re int i=0;i<26;i++) son[y][i]=son[x][i];
        while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
    }
}S1,S2;
int n;
LL pre[maxn],beh[maxn];
int len[maxn],fa[maxn],son[maxn][26],mx[maxn],mi[maxn];
int lst=1,cnt=1;
int tax[maxn>>1],a[maxn];
LL c[maxn],t[maxn];
inline void extend(int c,int o) {
    int p=++cnt,f=lst;lst=p;
    len[p]=len[f]+1,mx[p]=mi[p]=o;
    while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    if(!f) {fa[p]=1;return;}
    int x=son[f][c];
    if(len[f]+1==len[x]) {fa[p]=x;return;}
    int y=++cnt;len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
    for(re int i=0;i<26;i++) son[y][i]=son[x][i];
    while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
}
int main() {
    scanf("%d",&n);scanf("%s",S+1);S1.lst=S1.cnt=1;S2.lst=S2.cnt=1;
    for(re int i=1;i<=n;i++) S1.ins(S[i]-'a'),pre[i]=S1.tot;
    for(re int i=n;i;i--) S2.ins(S[i]-'a'),beh[i]=S2.tot;
    memset(mi,20,sizeof(mi));
    for(re int i=1;i<=n;i++) extend(S[i]-'a',i);
    for(re int i=1;i<=cnt;i++) tax[len[i]]++;
    for(re int i=1;i<=n;i++) tax[i]+=tax[i-1];
    for(re int i=cnt;i;--i) a[tax[len[i]]--]=i;
    for(re int i=cnt;i;--i) {
        int x=a[i];
        mx[fa[x]]=max(mx[fa[x]],mx[x]);mi[fa[x]]=min(mi[fa[x]],mi[x]);
    }
    for(re int i=2;i<=cnt;i++) {
        if(mi[i]==mx[i]) continue;
        int L=mx[i]-len[i]+1,R=mx[i]-len[fa[i]]-1;
        if(L<=mi[i]+1) {
            L=mi[i]+1;int li=R-L+1;
            if(L>R) continue;
            t[L]+=li;
            t[L+1]+=-1-li;
            t[R+2]+=1;
            continue;
        }
        c[mi[i]+1]+=len[i]-len[fa[i]];c[L]-=len[i]-len[fa[i]];
        if(len[i]-len[fa[i]]>1) {
            if(L>R) continue;
            t[L]+=len[i]-len[fa[i]]-1;
            t[L+1]+=-len[i]+len[fa[i]];
            t[R+2]+=1;
        } 
    }
    for(re int i=1;i<=n;i++) t[i]+=t[i-1];
    for(re int i=1;i<=n;i++) c[i]+=c[i-1]+t[i];
    for(re int i=1;i<=n;i++) 
        printf("%lld ",pre[i-1]+beh[i+1]-c[i]+(LL)i*(LL)(n-i+1));
    puts("");
    return 0;
}

转载于:https://www.cnblogs.com/asuldb/p/10449890.html

基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集中的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展中的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值