zoukankan      html  css  js  c++  java
  • P5341 [TJOI2019]甲苯先生和大中锋的字符串(后缀自动机+差分数组维护)

    给出一个字符串。

    请你找出所有出现次数恰好为k次的子串中,出现次数最多的子串长度。

    先建出后缀自动机。

    每个节点所代表的子串长度区间为len[link[i]]+1到len[i]。

    每个节点所代表的子串出现次数是它的link树子树大小,

    用差分数组维护一下。

    //一个子串的出现次数=
    //它的link树子树大小
    //先找到link树子树大小恰好为k的节点
    //然后这个节点,管理的节点长度区间是len[i]~len[link[i]]-1
    //那么可以用差分数组维护每种长度的出现次数
    //然后就是答案?
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=3e5+100;
    int len[maxn],link[maxn],nxt[maxn][26],tot,lst,sz[maxn];
    vector<int> g[maxn];
    void clear () {
    	for (int i=0;i<=tot;i++) {
    		len[i]=link[i]=sz[i]=0;
    		g[i].clear();
    		for (int j=0;j<26;j++) nxt[i][j]=0;
    	}
    	tot=1;
    	lst=1;
    }
    string s;
    int k;
    void sam_extend (char c) {
    	int cur=++tot;
    	len[cur]=len[lst]+1;
    	sz[cur]=1;
    	int p=lst;
    	while (p&&!nxt[p][c-'a']) {
    		nxt[p][c-'a']=cur;
    		p=link[p];
    	}
    	if (!p) {
    		link[cur]=1;
    	}
    	else {
    		int q=nxt[p][c-'a'];
    		if (len[p]+1==len[q]) {
    			link[cur]=q;
    		}
    		else {
    			int clone=++tot;
    			len[clone]=len[p]+1;
    			for (int i=0;i<26;i++) {
    				nxt[clone][i]=nxt[q][i];
    			}
    			link[clone]=link[q];
    			while (p&&nxt[p][c-'a']==q) {
    				nxt[p][c-'a']=clone;
    				p=link[p];
    			}
    			link[q]=link[cur]=clone;
    		}
    	}
    	lst=cur;
    	sz[cur]=1;
    }
    int _;
    void dfs (int u) {
    	for (int v:g[u]) {
    		dfs(v);
    		sz[u]+=sz[v];
    	}
    }
    int d[maxn];
    int main ()  {
    	cin>>_;
    	while (_--) {
    		cin>>s>>k;
    		clear();
    		for (char i:s) sam_extend(i);
    		for (int i=2;i<=tot;i++) g[link[i]].push_back(i);
    		dfs(1);
    		for (int i=0;i<=s.size()+1;i++) d[i]=0;
    		for (int i=1;i<=tot;i++) {
    			if (sz[i]==k) {
    				d[len[i]+1]--;
    				d[len[link[i]]+1]++;
    			}
    		}
    		int Max=0;
    		int ans=-1;
    		int sum=0;
    		for (int i=1;i<=s.size();i++) {
    			sum+=d[i];
    			Max=max(Max,sum);
    		}
    		if (Max==0) {
    			printf("-1
    ");
    			continue;
    		}
    		sum=0;
    		for (int i=1;i<=s.size();i++) {
    			sum+=d[i];
    			if (sum==Max) ans=i;
    		}
    		printf("%d
    ",ans);
    	}
    }
  • 相关阅读:
    给定中序和后序遍历,求前序序列(C++递归方式实现)
    myeclipse2014删除antlr-2.7.2.jar--解决struts和hibernate包冲突
    hadoop1.2.1配置与运行子串统计程序
    任务计划crontab
    建NTP
    vnc下运行runInstall报java错误
    rpm软件安装
    redis
    rpm包和deb包转换
    新老版本centos下载
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/15016123.html
Copyright © 2011-2022 走看看