zoukankan      html  css  js  c++  java
  • 【洛谷P5341】甲苯先生和大中锋的字符串

    题目

    题目链接:https://www.luogu.com.cn/problem/P5341
    大中锋有一个长度为 (n) 的字符串,他只知道其中的一个子串是祖上传下来的宝藏的密码。但是由于字符串很长,大中锋很难将这些子串一一尝试。
    这天大中锋找到甲苯先生算命,但是甲苯先生说:“天机不可泄漏”。
    在大中锋的苦苦哀求下,甲苯先生告诉大中锋:“密码是在字符串中恰好出现了 (k) 次的子串”。
    但是大中锋不知道该怎么做,在大中锋再三的恳求下,甲苯先生看其真诚,又告诉他:“在恰好出现了 (k) 次的子串中,你去按照字串的长度分类,密码就在数量最多的那一类里”。
    大中锋为了尝试这个密码,想让你帮忙找出子串长度出现次数最多的长度数(如果有多个输出最长长度)。
    (1leq nleq 10^5,1 leq T leq 100,sum n leq 3 * 10^6)

    思路

    氵氵氵。
    恰好出现 (k) 次的子串显然等价于 (mathrm{endpos}) 集合大小等于 (k) 的子串,parent 树上乱搞就可以得到每一个节点 (mathrm{endpos}) 集合的大小。
    然后如果一个等价类的出现次数恰好为 (k),那么直接用差分把 (cnt_{mathrm{len[fa]+1}}sim cnt_{mathrm{len[x]}}) 全部加一。最后在 (cnt) 中找最大值即可。
    时间复杂度 (O(sum n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=200010;
    int Q,n,m,ans,cnt[N],a[N],c[N];
    char s[N];
    
    struct SAM
    {
    	int tot,last,ch[N][26],fa[N],len[N],siz[N];
    	
    	void ins(int c)
    	{
    		int p=last,np=++tot;
    		last=tot; len[np]=len[p]+1; siz[np]=1;
    		for (;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
    		if (!p) fa[np]=1;
    		else
    		{
    			int q=ch[p][c];
    			if (len[q]==len[p]+1) fa[np]=q;
    			else
    			{
    				int nq=++tot;
    				fa[nq]=fa[q]; len[nq]=len[p]+1;
    				for (int i=0;i<26;i++) ch[nq][i]=ch[q][i];
    				fa[q]=fa[np]=nq;
    				for (;p && ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
    			}
    		}
    	}
    	
    	void topsort()
    	{
    		for (int i=0;i<=tot;i++) c[i]=0;
    		for (int i=1;i<=tot;i++) c[len[i]]++;
    		for (int i=1;i<=tot;i++) c[i]+=c[i-1];
    		for (int i=1;i<=tot;i++) a[c[len[i]]--]=i;
    		for (int i=tot;i>=1;i--)
    		{
    			int j=a[i];
    			siz[fa[j]]+=siz[j];
    			if (j!=1 && siz[j]==m) cnt[len[fa[j]]+1]++,cnt[len[j]+1]--;
    		}
    	}
    }sam;
    
    void prework()
    {
    	for (int i=0;i<=sam.tot;i++)
    	{
    		sam.fa[i]=sam.len[i]=sam.siz[i]=0;
    		memset(sam.ch[i],0,sizeof(sam.ch[i]));
    	}
    	sam.tot=sam.last=1;
    	for (int i=0;i<=n;i++) cnt[i]=0;
    }
    
    int main()
    {
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		prework();
    		scanf("%s%d",s+1,&m);
    		n=strlen(s+1);
    		for (int i=1;i<=n;i++)
    			sam.ins(s[i]-'a');
    		sam.topsort();
    		ans=0;
    		for (int i=1;i<=n;i++)
    		{
    			cnt[i]+=cnt[i-1];
    			if (cnt[i] && cnt[i]>=cnt[ans]) ans=i;
    		}
    		if (ans) printf("%d
    ",ans);
    			else printf("-1
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    关于SQLite
    Solr开发文档
    Using Fiddler with IIS
    SQL SERVER – Difference Between Union vs. Union All – Optimal Performance Comparison
    Git资料
    VS2010版快捷键
    IE9子iframe父iframe cookie设置诡异问题
    美国的企业家宣言
    互联网程序编写原则
    分析牛人js版删除代码注释(状态机机制)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14304863.html
Copyright © 2011-2022 走看看