• [TJOI2019]甲苯先生和大中锋的字符串


    IV.[TJOI2019]甲苯先生和大中锋的字符串

    判断一个子串出现几次,我们仍然可以采取之前提到的遍历parent tree的方法。

    考虑一个等价类。明显,这个等价类中所有串都出现且仅出现了(等价类出现的次数)。若这个次数恰好为 \(k\),则从类中最长的串到最短的串,所有长度的串的数量都增加了 \(1\)。于是用一个差分数组维护这一过程,最后找到其中出现最多的长度即可。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int T,cnt,n,m;
    struct Suffix_Automaton{int ch[26],len,fa;}t[200100];
    int sz[200100];
    int Add(int x,int c){
    	int xx=++cnt;t[xx].len=t[x].len+1;
    	sz[xx]=1;
    	for(;x&&!t[x].ch[c];x=t[x].fa)t[x].ch[c]=xx;
    	if(!x){t[xx].fa=1;return xx;}
    	int y=t[x].ch[c];
    	if(t[y].len==t[x].len+1){t[xx].fa=y;return xx;}
    	int yy=++cnt;t[yy]=t[y];
    	t[yy].len=t[x].len+1;
    	t[y].fa=t[xx].fa=yy;
    	for(;x&&t[x].ch[c]==y;x=t[x].fa)t[x].ch[c]=yy;
    	return xx;
    }
    vector<int>v[200100];
    ll d[100100],mx;
    void dfs(int x){for(auto y:v[x])dfs(y),sz[x]+=sz[y];}
    char s[100100];
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		scanf("%s%d",s,&m),n=strlen(s),cnt=1,mx=0;
    		for(int i=0,las=1;i<n;i++)las=Add(las,s[i]-'a');
    		for(int i=2;i<=cnt;i++)v[t[i].fa].push_back(i);
    		dfs(1);
    		for(int i=2;i<=cnt;i++)if(sz[i]==m)d[t[t[i].fa].len]--,d[t[i].len]++;
    		for(int i=n;i;i--)d[i]+=d[i+1],mx=max(mx,d[i]);
    		if(!mx)puts("-1");
    		else for(int i=n;i;i--)if(d[i]==mx){printf("%d\n",i);break;}
    		for(int i=1;i<=cnt;i++){memset(t[i].ch,0,sizeof(t[i].ch)),t[i].len=t[i].fa=sz[i]=0,v[i].clear();}
    		for(int i=1;i<=n;i++)d[i]=0;
    	}
    	return 0;
    } 
    

  • 相关阅读:
    bzoj 1017 魔兽地图DotR
    poj 1322 chocolate
    bzoj 1045 糖果传递
    poj 3067 japan
    timus 1109 Conference(二分图匹配)
    URAL 1205 By the Underground or by Foot?(SPFA)
    URAL 1242 Werewolf(DFS)
    timus 1033 Labyrinth(BFS)
    URAL 1208 Legendary Teams Contest(DFS)
    URAL 1930 Ivan's Car(BFS)
  • 原文地址:https://www.cnblogs.com/Troverld/p/14605673.html
Copyright © 2020-2023  润新知