zoukankan      html  css  js  c++  java
  • spoj New Distinct Substrings

    vjudge原地爆炸...

    题意:求一个字符串不同的子串的个数

    策略:后缀数组

    利用后缀数组的sa和height两个功能强大的数组,我们可以实现上述操作

    首先有个很显然的结论:一个字符串的所有子串=它后缀的所有前缀

    这是很显然的,因为一个后缀的前缀遍历了所有以该后缀起点为起点的字符串的子串,那么如果我们遍历所有后缀的,就能找出这个字符串的所有子串了

    所以对于一个起点为sa[i]的字符串,最多能提供的贡献就是l-sa[i]+1,而再考虑重复字符串的个数,也就是这个后缀所有的与其他后缀最长的公共前缀,这个后缀的贡献就是l-sa[i]+1-height[i]

    然后累计即可

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
    int sa[50005];
    int rk[50005];
    int height[50005];
    int f1[50005];
    int f2[50005];
    int f3[50005];
    int has[50005];
    char s[50005];
    int l,m=127;
    void init()
    {
    	memset(sa,0,sizeof(sa));
    	memset(rk,0,sizeof(rk));
    	memset(has,0,sizeof(has));
    	memset(f1,0,sizeof(f1));
    	memset(f2,0,sizeof(f2));
    	memset(f3,0,sizeof(f3));
    	memset(height,0,sizeof(height));
    	m=127;
    }
    void turnit()
    {
    	memcpy(f3,f1,sizeof(f3));
    	memcpy(f1,f2,sizeof(f1));
    	memcpy(f2,f3,sizeof(f2));
    }
    void get_sa()
    {
    	for(int i=1;i<=l;i++)
    	{
    		f1[i]=s[i];
    		has[f1[i]]++;
    	}
    	for(int i=2;i<=m;i++)
    	{
    		has[i]+=has[i-1];
    	}
    	for(int i=l;i>=1;i--)
    	{
    		sa[has[f1[i]]--]=i;
    	}
    	for(int k=1;k<=l;k<<=1)
    	{
    		int tot=0;
    		for(int i=l-k+1;i<=l;i++)
    		{
    			f2[++tot]=i;
    		}
    		for(int i=1;i<=l;i++)
    		{
    			if(sa[i]>k)
    			{
    				f2[++tot]=sa[i]-k;
    			}
    		}
    		for(int i=1;i<=m;i++)
    		{
    			has[i]=0;
    		}
    		for(int i=1;i<=l;i++)
    		{
    			has[f1[i]]++;
    		}
    		for(int i=2;i<=m;i++)
    		{
    			has[i]+=has[i-1];			
    		}
    		for(int i=l;i>=1;i--)
    		{
    			sa[has[f1[f2[i]]]--]=f2[i];
    			f2[i]=0;
    		}
    		turnit();
    		f1[sa[1]]=1;
    		tot=1;
    		for(int i=2;i<=l;i++)
    		{
    			if(f2[sa[i]]==f2[sa[i-1]]&&f2[sa[i]+k]==f2[sa[i-1]+k])
    			{
    				f1[sa[i]]=tot;
    			}else
    			{
    				f1[sa[i]]=++tot;
    			}
    		}
    		if(tot==l)
    		{
    			break;
    		}
    		m=tot;
    	}
    	for(int i=1;i<=l;i++)
    	{
    		rk[sa[i]]=i;
    	}
    	int f=0;
    	for(int i=1;i<=l;i++)
    	{
    		if(rk[i]==1)
    		{
    			continue;
    		}
    		if(f)
    		{
    			f--;
    		}
    		int j=sa[rk[i]-1];
    		while(s[i+f]==s[j+f])
    		{
    			f++;
    		}
    		height[rk[i]]=f;
    	}
    }
    void solve()
    {
    	int ss=0;
    	for(int i=1;i<=l;i++)
    	{
    		ss-=l-sa[i]+1-height[i];
    	}
    	printf("%d
    ",ss);
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		init();
    		scanf("%s",s+1);
    		l=strlen(s+1);
    		get_sa();
    		solve();
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    二分查找
    Android手机APN设置(中国移动 联通3G 电信天翼),解决不能上网的问题
    cocos2dx 3.1从零学习(三)——Touch事件(回调,反向传值)
    Groovy新手教程
    总结一下用caffe跑图片数据的研究流程
    JAVA数组的定义及用法
    开机黑屏 仅仅显示鼠标 电脑黑屏 仅仅有鼠标 移动 [已成功解决]
    LeetCode——Reverse Words in a String
    oracle 库文件解决的方法 bad ELF interpreter: No such file or directory
    布局文件提示错误“No orientation specified, and the default is horizontal. This is a common so...”
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9708939.html
Copyright © 2011-2022 走看看