[SMOJ1813]不同子串个数
来源:互联网 发布:手机淘宝网试衣间在哪 编辑:程序博客网 时间:2024/06/05 02:49
题目描述
给定一个包含大小写字母的字符串和当中可能出现的不同字符数
NC ,求该字符串中长度为N 的不同子串个数。
例如,考虑N=3,NC=4 和字符串“daababac”。在串中可以找到的大小为 3 的不同子字符串是:“daa”; “aab”; “aba” “bab” “bac”。
所以答案应该是 5。
输入格式 1813.in
第一行输入由两个数字
N 和NC 组成,分隔一个空格。之后是一行字符串,长度不超过1600万。
输出格式 1813.out
输出一个在给定字符串中找到的长度为
N 的不同子串个数。
输入样例 1813.in
3 4
daababac
输出样例 1813.out
5
提示
输入量较大,C++选手建议使用scanf。
考虑到数据范围是比较大的,假设我们要枚举每个子串,然后逐位编码,得到一个 hash 值,如果该值曾经出现过就不计数,否则答案加 1,并将该值标记。
这种做法的时间复杂度应该是
问题的关键在于一种将整个串编码,还能分解出子串编码的方式。这里介绍一种字符串编码的方法。
首先我们会想一下二进制数。
对于任意一个二进制数,我们将它化为 10 进制的数的方法如下(以二进制数 1101101 为例):
hash 用的也是一样的原理,为每一个前缀,
一般地,
而对于
但是如果
因此我们把 hash 值每计算一次就对一个较大的质数
还有,多次计算的时候,权
因此我们可以通过 Hash 值来比较两个字符串是否相等。
给出字符串 hash 的处理:
char s[N];int hash[N];void init(){ //处理hash值 p[0] = 1; hash[0] = 0; int n = strlen(s + 1); for (int i = 1; i <= 100000; i++) p[i] = (p[i - 1] * base) % Prime; for (int i = 1; i <= n; i++) hash[i] = (hash[i - 1] * base + (s[i] - 'A')) % Prime;}int get(int l, int r){ //取出 [l, r] 里面的字符串的 hash 值 return (hash[r] - hash[l - 1] * p[r - l + 1] + Prime) % Prime;}
用这样的方法给本题中的字符串编码,再枚举每个子串的开头或结尾,通过
此题的POJ(1200)数据很水,请勿轻信网上的所谓“AC”程序,大部分都是错的
以下代码来自gsh:
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<vector>using namespace std;#define MOD 4933333LL#define Maxn 5000003char s[Maxn];bool hash[MOD];bool hash2[MOD];bool hash3[MOD];bool hash4[MOD];bool hash5[MOD];bool hash6[MOD];long long sum[Maxn];long long kum[Maxn];long long lum[Maxn];long long mum[Maxn];long long num[Maxn];long long oum[Maxn];int find(long long h){ if(hash[h]==true)return 0; hash[h]=true; return 1;}int find2(long long h){ if(hash2[h]==true)return 0; hash2[h]=true; return 1;}int find3(long long h){ if(hash3[h]==true)return 0; hash3[h]=true; return 1;}int find4(long long h){ if(hash4[h]==true)return 0; hash4[h]=true; return 1;}int find5(long long h){ if(hash5[h]==true)return 0; hash5[h]=true; return 1;}int find6(long long h){ if(hash6[h]==true)return 0; hash6[h]=true; return 1;}int n,nc;long long ans;int main(){ freopen("1813.in","r",stdin); freopen("1813.out","w",stdout); scanf("%d%d",&n,&nc) ; ans = 0; scanf("%s",&s); int len=strlen(s); if(len<n) { puts("0"); return 0; } long long p=1,pp=1,ppp=1,pppp=1,ppppp=1,pppppp=1; for(int i=1;i<=n;i++)p=p*31LL%MOD; for(int i=1;i<=n;i++)pp=pp*233LL%MOD; for(int i=1;i<=n;i++)ppp=ppp*107LL%MOD; for(int i=1;i<=n;i++)pppp=pppp*131LL%MOD; for(int i=1;i<=n;i++)ppppp=ppppp*1313LL%MOD; for(int i=1;i<=n;i++)pppppp=pppppp*1331LL%MOD; sum[0]=s[0];kum[0]=s[0];lum[0]=s[0];mum[0]=s[0];num[0]=s[0];oum[0]=s[0]; for(int i=1;i<len;i++) { sum[i]=(sum[i-1]*31LL+s[i])%MOD; kum[i]=(kum[i-1]*233LL+s[i])%MOD; lum[i]=(lum[i-1]*107LL+s[i])%MOD; mum[i]=(mum[i-1]*131LL+s[i])%MOD; num[i]=(num[i-1]*1313LL+s[i])%MOD; oum[i]=(oum[i-1]*1331LL+s[i])%MOD; } ans=0; for(int i=n-1;i<len;i++) { if(i>=n) { long long f=(sum[i]-(sum[i-n]*p)%MOD+MOD)%MOD; long long ff=(kum[i]-(kum[i-n]*pp)%MOD+MOD)%MOD; long long fff=(lum[i]-(lum[i-n]*ppp)%MOD+MOD)%MOD; long long ffff=(mum[i]-(mum[i-n]*pppp)%MOD+MOD)%MOD; long long fffff=(num[i]-(num[i-n]*ppppp)%MOD+MOD)%MOD; long long ffffff=(oum[i]-(oum[i-n]*pppppp)%MOD+MOD)%MOD; int delta= max(max(max(find(f), find2(ff)), max(find3(fff), find4(ffff))), max(find5(fffff), find6(ffffff))); if (delta) ans++; } else { long long f=sum[i]; long long ff=kum[i]; long long fff=lum[i]; long long ffff=mum[i]; long long fffff=num[i]; long long ffffff=oum[i]; int delta= max(max(max(find(f), find2(ff)), max(find3(fff), find4(ffff))), max(find5(fffff), find6(ffffff))); if(delta)ans++; } } printf("%lld\n",ans); return 0;}
- [SMOJ1813]不同子串个数
- 【后缀数组】【不同子串个数】DISUBSTR spoj694/705
- spoj 694 求不同子串的个数
- 后缀自动机(不同子串的个数)hdu4416
- HDU 4622 本质不同的子串个数:后缀自动机
- HDOJ4029 不同子矩阵的个数
- Distinct Subsequences 不同的子序列个数
- hdu3948——后缀数组统计不同回文子串的个数
- HDU 4622 Reincarnation(SAM 后缀自动机 求子串的不同子串个数)
- spoj 694 Distinct Substrings(求不同的子串个数,后缀数组基础题)
- SPOJ 694/705 Distinct Substrings ( 后缀数组 不同子串个数 )
- spoj 694 求一个字符串中不同子串的个数
- spoj 694 求一个字符串中不同子串的个数
- HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)
- SPOJ 题目694 Distinct Substrings(后缀数组,求不同的子串个数)
- SPOJ 题目705 New Distinct Substrings(后缀数组,求不同的子串个数)
- spoj694 Distinct Substrings(后缀数组+统计不同子串的个数)
- spoj 405 求不同子串的个数 后缀数组和高度数组的应用
- PHP 遍历多维数组成一维,(数组元素可为对象)
- 【Android View绘制体系】invalidate
- svn 锁住了,并且无法clean up 的解决方法
- Multiple dex files define Lorg/kobjects/base64/Base64;
- Mysql安装与c++使用mysql
- [SMOJ1813]不同子串个数
- SpringBoot + MyBatis + DRUID + MySQL Maven依赖配置
- numCk
- 首席架构师修炼真经:除经验技术能力外,还要有领导力!
- Linux下父子进程匿名管道通信
- Java Lambda(5)
- 题目1182:统计单词
- ReentrantLock与Condition
- rails number_to_percentage 百分比的应用