HDU 4436 str2int 后缀数组 字符串哈希 前缀和
2014-09-12 15:29
411 查看
题意:给出N个数字序列,每个序列的子串都能组成数字。求出这些序列所有子串对应的数字的和。对于相同的数字,我们只考虑一次。忽略前导零。
思路:(以前都是做单个字符串的题,第一次做多个字符串的题,跪了。。。只知道思想,不写出代码还是不会呀。下面是看网上题解才明白的。)
我们可以用后缀数组求出所有的不相同的子串。但是我们怎么求出对应字符串的和呢?
这里就用到了字符串哈希的思想。我们可以求出到第i位,1-i位数字的值(即前缀和),然后我们再求出前缀和的前缀和。同时,我们记录进制数的前缀和。这样,我们就O(1)求出任意[l,r]内对应子串能产生的所有数字的和。
代码来自/article/8985268.html
学姿势:
1.在字符串中求值,注意哈希的使用。
2.多个字符串拼成一个,记录位置。
3.前缀和
思路:(以前都是做单个字符串的题,第一次做多个字符串的题,跪了。。。只知道思想,不写出代码还是不会呀。下面是看网上题解才明白的。)
我们可以用后缀数组求出所有的不相同的子串。但是我们怎么求出对应字符串的和呢?
这里就用到了字符串哈希的思想。我们可以求出到第i位,1-i位数字的值(即前缀和),然后我们再求出前缀和的前缀和。同时,我们记录进制数的前缀和。这样,我们就O(1)求出任意[l,r]内对应子串能产生的所有数字的和。
代码来自/article/8985268.html
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> #include <map> #include <queue> #define maxn 300000 #define MOD 2012 using namespace std; int wa[maxn],wb[maxn],wv[maxn]; int rank[maxn],height[maxn],wS[maxn],sa[maxn],P[maxn],Pow[maxn],V[maxn], T[maxn],Len[maxn],S[maxn],arrive[maxn],n,len,value; char s[maxn]; int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];} void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) wS[i]=0; for(i=0;i<n;i++) wS[x[i]=r[i]]++; for(i=1;i<m;i++) wS[i]+=wS[i-1]; for(i=n-1;i>=0;i--) sa[--wS[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p) { for(p=0,i=n-j;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++) wv[i]=x[y[i]]; for(i=0;i<m;i++) wS[i]=0; for(i=0;i<n;i++) wS[wv[i]]++; for(i=1;i<m;i++) wS[i]+=wS[i-1]; for(i=n-1;i>=0;i--) sa[--wS[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } return; } void calheight(int *r,int *sa,int n) { int i,j,k=0; for(i=0;i<n;i++) rank[sa[i]]=i; for(i=0;i<n;height[rank[i++]]=k) if(rank[i])for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); return; } int get(int l,int r) { if(l>r) return 0; int ans=(T[r+1]-T[l])%MOD; //ans-=V[l]*(Pow[r]-(l?Pow[l-1]:0)); ans-=V[l]*(Pow[r-l+1]); ans%=MOD; if (ans<0) ans+=MOD; return ans; } int main() { Pow[0]=1;Pow[1]=10; for (int i=2;i<200000;++i) Pow[i]=(Pow[i-1]+1)*10%MOD; while (scanf("%d",&n)!=EOF) { len = 0; value = 0; for (int i=0;i < n ;++i){ scanf("%s",s); Len[i]= strlen(s); for (int j = 0 ; j < Len[i]; ++j){ S[len]=s[j]-'0'+1; value = (value*10+S[len]-1)%MOD; V[len+1]=value; T[len+1]=(T[len]+value)%MOD; P[len]=i; len++; } S[len]=11; value = (value*10+10)%MOD; V[len+1]=value; T[len+1]=(T[len]+value)%MOD; P[len]=i; len++; arrive[i]=len-2; } S[len-1]=0; da(S,sa,len,12); //for (int i=0;i<len;++i) cout << sa[i]<<" ";cout<<endl; calheight(S,sa,len); //for (int i=0;i<len;++i) cout << rank[i]<<" ";cout<<endl; //cout<<len<<endl; int ans = 0; for (int i = 0;i < len;++i) if (S[i]%10 !=1){ if (i+height[rank[i]]<= arrive[P[i]]){ ans+=get(i,arrive[P[i]])-get(i,i+height[rank[i]]-1); ans%=MOD;if (ans<0) ans+=MOD; } } cout << ans << endl; } return 0; }
学姿势:
1.在字符串中求值,注意哈希的使用。
2.多个字符串拼成一个,记录位置。
3.前缀和
相关文章推荐
- HDU 4436 str2int(后缀数组,一种统计n个digit字符串所有不同子串之和的方法)
- HDU 4436 str2int 后缀数组 + 前缀和预处理 或 后缀自动机
- HDU 4622 Reincarnation (区间不相同子串个数:字符串哈希 | 后缀数组 | 后缀自动机)
- hdu 4436 str2int 后缀数组、后缀自动机
- [珠玑之椟]字符串和序列:左移、哈希、最长重复子序列的后缀数组解法、最大连续子序列
- 字符串相关处理kmp,前缀数,后缀树,后缀数组,最长回文串,最长重复字串,最长非重复字串
- HDU 4436 str2int 后缀数组(前缀和预处理)
- HDU 4436 str2int【后缀自动机】
- [珠玑之椟]字符串和序列:左移、哈希、最长重复子序列的后缀数组解法、最大连续子序列
- hdu 4436 str2int (后缀自动机+dp)
- [ACM] hdu 5147 Sequence II (树状数组,前缀和,后缀和)
- 求所有前缀-后缀字符串相等的长度(kmp算法中的nxet数组)
- [珠玑之椟]字符串和序列:左移、哈希、最长重复子序列的后缀数组解法、最大连续子序列
- HDU 4436 str2int (后缀自动机)
- hdu1403---Longest Common Substring(后缀数组求2个字符串的最长公共子串)
- HDU 4436 str2int(后缀自动机)
- [珠玑之椟]字符串和序列:左移、哈希、最长重复子序列的后缀数组解法、最大连续子序列
- HDU 4436 str2int (后缀自动机SAM,多串建立)
- hdu 4436 str2int(后缀自动机)
- 字符串相关处理kmp,前缀数,后缀树,后缀数组,最长回文串,最长重复字串,最长非重复字串