hdu 4436 str2int 后缀数组
2013-11-13 00:49
253 查看
递推的办法不难想到,但是要去重,那就要后缀数组来找最长前缀了。后面递推的没想好,写搓了。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <set> using namespace std; const int maxn=1e5+1e5+9,mod=2012; char a[maxn]; int r[maxn]; int next[maxn]; long long dp[maxn]; int prel[maxn],sum[maxn],pp[maxn],ff[maxn]; int minrmq[maxn][20]; int *rank,height[maxn],sa[maxn]; int wx[maxn],wy[maxn],cnt[maxn];//后缀数组使用的过程数组 //height排名为i和i-1的后缀的最长前缀,rank后缀的排名,sa排名为i的后缀的起始位置。 inline bool cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } //n为字符串长度,m为最大的字符的值。 void da(int *r,int n,int m)//r数组不能出现0 { r[n+1]=0; int i,l,p,*x=wx,*y=wy,*t; memset(cnt,0,sizeof(int)*(m+1)); for(int i=1;i<=n;i++) cnt[x[i]=r[i]]++; for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(int i=n;i>=1;i--) sa[cnt[x[i]]--]=i; for(l=1,p=1;p<n;l<<=1,m=p) { for(p=1,i=n-l+1;i<=n;i++) y[p++]=i; for(i=1;i<=n;i++) if(sa[i]>l) y[p++]=sa[i]-l; memset(cnt,0,sizeof(int)*(m+1)); for(i=1;i<=n;i++) cnt[x[i]]++; for(i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(i=n;i>=1;i--) sa[cnt[x[y[i]]]--]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[1]]=1,i=2;i<=n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],l)?p:++p; } rank=x; int j,k=0; for(i=1;i<=n;height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); return; } void getrmq(int n)//n为数据大小 { for(int i=1;i<=n;i++) minrmq[i][0]=height[i]; for(int i=1;(1<<i)<=n;i++) for(int j=1;j+(1<<i)-1<=n;j++) minrmq[j][i]=min(minrmq[j][i-1],minrmq[j+(1<<i-1)][i-1]); } int askrmq(int t,int s) { int k=log((double)s-t+1)/log((double)2); int mmin=min(minrmq[t][k],minrmq[s-(1<<k)+1][k]); return mmin; } void getpre(int n) { set <int> s; s.clear(); for(int i=1;i<=n;i++) { set <int> :: iterator p=s.lower_bound(rank[n-i+1]); if(p!=s.end()) { prel[i]=askrmq(rank[n-i+1]+1,*p); } if(p!=s.begin()) { p--; prel[i]=max(prel[i],askrmq((*p)+1,rank[n-i+1])); } s.insert(rank[n-i+1]); } next[1]=1; for(int i=2;i<=n;i++) { if(a[i-1]=='0') { next[i]=next[i-1]; } else next[i]=i; } // for(int i=1;i<=n;i++) // { // if(prel[i]!=0) // prel[i]+=i-prel[i]+1-next[i-prel[i]+1]; //// else //// prel[i]+=i-next[i]+1; // } } int zero[maxn]; void solve(int n) { dp[0]=0; sum[0]=0; ff[0]=0; bool flag=false; a[0]='#'; for(int i=0,k=1,m=(a[i]!=0);i<=n;i++) { if(a[i]=='#') { zero[i]=0; sum[i]=0; dp[i]=dp[i-1]; k=0; m=0; ff[i]=0; flag=false; while(a[i+1]=='0') { ff[i]=0; sum[i]=0; i++; dp[i]=dp[i-1]; zero[i]=0; } } else { k++; sum[i]=(sum[i-1]*10+(a[i]-'0')*(k-m))%mod; ff[i]=(ff[i-1]*10+a[i]-'0')%mod; dp[i]=(dp[i-1]+sum[i])%mod; int tmp=(ff[i]-ff[i-prel[i]]*pp[prel[i]]+mod*mod)%mod; dp[i]-=sum[i]-(sum[i-prel[i]]*pp[prel[i]]+tmp*(k-prel[i]-zero[i-prel[i]])); dp[i]=(dp[i]+(long long)2012000000*10)%mod; zero[i]=zero[i-1]; if(a[i]=='0') { m++; zero[i]++; } // else m=0; } } cout<<dp[n-1]<<endl; } void getpp() { pp[0]=1; for(int i=1;i<maxn;i++) pp[i]=(pp[i-1]*10)%mod; } int main() { freopen("in.txt","r",stdin); int T; while(scanf("%d",&T)!=EOF) { memset(prel,0,sizeof(prel)); int n=0; char txt; getchar(); for(int i=1;i<=T;i++) { while(1) { txt=getchar(); if(txt==' ') continue; if(txt=='0') continue; break; } while(1) { if(txt=='\n') break; if(txt==' ') { txt=getchar(); continue; } a[++n]=txt; txt=getchar(); } a[++n]='#'; } for(int i=1,t=0;i<=n;i++) { if(a[n-i+1]!='#') r[i]=a[n-i+1]; else { t++; r[i]='9'+t; } } da(r,n,'9'+T); getrmq(n); getpre(n); getpp(); solve(n); // for(int i=1;i<=n;i++) // cout<<prel[i]<<endl; } return 0; }
相关文章推荐
- HDU 4436 str2int 后缀数组(前缀和预处理)
- hdu 4436 str2int(后缀数组)
- HDU 4436 str2int
- hdu 4436 str2int (SAM)(待补)
- HDU 4436 str2int 后缀数组 + 前缀和预处理 或 后缀自动机
- HDU 4436 后缀数组
- HDU 4436 str2int(后缀自动机)
- hdu 4436 str2int(后缀自动机)
- HDU 4436 str2int(后缀数组,一种统计n个digit字符串所有不同子串之和的方法)
- HDU 4436 str2int(后缀自动机)
- HDU 4436 str2int (后缀自动机SAM,多串建立)
- Hdu 4436 str2int 后缀自动机
- HDU 4436 str2int(后缀自动机)(2012 Asia Tianjin Regional Contest)
- HDU 4436 str2int
- hdu 4436 str2int (SAM)
- HDU 4436 str2int (后缀自动机SAM,多串建立)
- HDU 4436 str2int(12年天津区域赛-F题-SA|SAM)
- hdu 4436 str2int (后缀自动机+dp)
- hdu 4436 str2int 后缀数组、后缀自动机
- hdu 4436 str2int(后缀自动机)