zoukankan      html  css  js  c++  java
  • 「hihocoder1413 Rikka with String」

    题目

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

    好像前后调了两天了

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

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

    首先就是跨过这个特殊字符的字符串出现次数显然都是(1),这部分的贡献就直接是(i imes(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;
    }
    
  • 相关阅读:
    hdu 5224 Tom and paper 水题
    2015 UESTC 搜索专题N题 韩爷的梦 hash
    2015 UESTC 搜索专题M题 Palindromic String 马拉车算法
    2015 UESTC 搜索专题K题 秋实大哥の恋爱物语 kmp
    2015 UESTC 搜索专题J题 全都是秋实大哥 kmp
    2015 UESTC 搜索专题F题 Eight Puzzle 爆搜
    2015 UESTC 搜索专题E题 吴队长征婚 爆搜
    2015 UESTC 搜索专题D题 基爷的中位数 二分
    2015 UESTC 搜索专题C题 基爷与加法等式 爆搜DFS
    2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索
  • 原文地址:https://www.cnblogs.com/asuldb/p/10449890.html
Copyright © 2011-2022 走看看