bzoj5137 Usaco2017Dec Standing Out from the Herd

http://www.elijahqi.win/2018/02/08/bzoj5137/

题目描述

Just like humans, cows often appreciate feeling they are unique in some way. Since Farmer John’s cows all come from the same breed and look quite similar, they want to measure uniqueness in their names.

Each cow’s name has some number of substrings. For example, “amy” has substrings {a, m, y, am, my, amy}, and “tommy” would have the following substrings: {t, o, m, y, to, om, mm, my, tom, omm, mmy, tomm, ommy, tommy}.

A cow name has a “uniqueness factor” which is the number of substrings of that name not shared with any other cow. For example, If amy was in a herd by herself, her uniqueness factor would be 6. If tommy was in a herd by himself, his uniqueness factor would be 14. If they were in a herd together, however, amy’s uniqueness factor would be 3 and tommy’s would be 11.

Given a herd of cows, please determine each cow’s uniqueness factor.

定义一个字符串的「独特值」为只属于该字符串的本质不同的非空子串的个数。如 “amy” 与 “tommy” 两个串,只属于 “amy” 的本质不同的子串为 “a” “am” “amy” 共 3 个。只属于 “tommy” 的本质不同的子串为 “t” “to” “tom” “tomm” “tommy” “o” “om” “omm” “ommy” “mm” “mmy” 共 11 个。 所以 “amy” 的「独特值」为 3 ,”tommy” 的「独特值」为 11 。

给定 N (

N≤105N \leq 10^5

N≤105 ) 个字符集为小写英文字母的字符串,所有字符串的长度和小于

10510^5

105 ,求出每个字符串「独特值」。
输入输出格式

输入格式:

The first line of input will contain

NN

N (

1≤N≤1051 \le N \le 10^5

1≤N≤105 ). The following

NN

N lines will each contain the name of a cow in the herd. Each name will contain only lowercase characters a-z. The total length of all names will not exceed

10510^5

105 .

输出格式:

Output

NN

N numbers, one per line, describing the uniqueness factor of each cow.
输入输出样例

输入样例#1: 复制

3
amy
tommy
bessie

输出样例#1: 复制

3
11
19

蒟蒻我不会sam只能用学习leoly 用sa来搞

那么针对每个串首先把他们连起来 然后加上分隔符 跑后缀数组 然后得到了按照字典序排序的这个东西 那么我想起了之前一道题 要求求自己这个字符串中本质不同的子串有多少个 可以想到直接n*(n+1)/2-height即可 这个其实可以同理 在自己中出现的只能算一次 如果在其他串中也出现了对答案的贡献就是0 那么我同理 直接减去 就可以了 但是还要注意一点 就是 针对 我一个字串如果他的后缀在sa中是一串连续的区间比如l~r那么我们这儿做之后别忘了加上lcp(l-1,r+1) 因为我相当于针对每个后缀都减掉了他们的lcp 那么是不是减多了 如果上与下匹配是aaa aaaaa 那么是不是这个对答案的贡献还有一个aaa而不是两个 所以要加回来

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 220000
#define ll long long
using namespace std;
int n,m,s[N],cnt[N],rk[N<<1],rk1[N],height[N],sa[N],pos[N],tmp[N],r[N];
char s1[N];ll ans[N];
int main(){
    freopen("bzoj5137.in","r",stdin);
    scanf("%d",&m);int st=26,k=0;
    for (int i=1;i<=m;++i){
        scanf("%s",s1+1);int nn=strlen(s1+1);
        for (int j=1;j<=nn;++j) s[++n]=s1[j]-'a'+1,pos[n]=i;r[i]=n;s[++n]=++st;
    }
    for (int i=1;i<=n;++i) cnt[s[i]]=1;
    for (int i=1;i<=st;++i) cnt[i]+=cnt[i-1];
    for (int i=1;i<=n;++i) rk[i]=cnt[s[i]];
    for (int p=1;k!=n;p<<=1,st=k){
        for (int i=1;i<=st;++i) cnt[i]=0;
        for (int i=1;i<=n;++i) ++cnt[rk[i+p]];
        for (int i=1;i<=st;++i) cnt[i]+=cnt[i-1];
        for (int i=n;i;--i) tmp[cnt[rk[i+p]]--]=i;
        for (int i=1;i<=st;++i)  cnt[i]=0;
        for (int i=1;i<=n;++i) ++cnt[rk[i]];
        for (int i=1;i<=st;++i) cnt[i]+=cnt[i-1];
        for (int i=n;i;--i) sa[cnt[rk[tmp[i]]]--]=tmp[i];
        memcpy(rk1,rk,sizeof(rk)>>1);rk[sa[1]]=k=1;
        for (int i=2;i<=n;++i){
            if (rk1[sa[i]]!=rk1[sa[i-1]]||rk1[sa[i]+p]!=rk1[sa[i-1]+p]) ++k;
            rk[sa[i]]=k;
        }
    }k=0;int mn=0;
    for (int i=1;i<=n;++i) {
        if (rk[i]==1) continue;
        k=k==0?0:k-1; 
        while(s[i+k]==s[sa[rk[i]-1]+k]) ++k;height[rk[i]]=k;
    }
    for (int i=1;i<=n;++i){
        if (s[sa[i-1]]>=27) break;int x=pos[sa[i]],y=pos[sa[i-1]];
        mn=min(mn,height[i]);ans[x]+=r[x]-sa[i]+1-height[i];
        if (x!=y) ans[y]-=height[i],ans[y]+=mn,mn=height[i];
    }
    for (int i=1;i<=m;++i) printf("%lld\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值