HDU 4436 str2int(后缀数组,一种统计n个digit字符串所有不同子串之和的方法)

来源:互联网 发布:初学者学linux 编辑:程序博客网 时间:2024/06/01 08:11

str2int

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1448    Accepted Submission(s): 500


Problem Description
In this problem, you are given several strings that contain only digits from '0' to '9', inclusive.
An example is shown below.
101
123
The set S of strings is consists of the N strings given in the input file, and all the possible substrings of each one of them.
It's boring to manipulate strings, so you decide to convert strings in S into integers.
You can convert a string that contains only digits into a decimal integer, for example, you can convert "101" into 101, "01" into 1, et al.
If an integer occurs multiple times, you only keep one of them. 
For example, in the example shown above, all the integers are 1, 10, 101, 2, 3, 12, 23, 123.
Your task is to calculate the remainder of the sum of all the integers you get divided by 2012.
 

Input
There are no more than 20 test cases.
The test case starts by a line contains an positive integer N.
Next N lines each contains a string consists of one or more digits.
It's guaranteed that 1≤N≤10000 and the sum of the length of all the strings ≤100000.
The input is terminated by EOF.
 

Output
An integer between 0 and 2011, inclusive, for each test case.
 

Sample Input
510112309000 1234567890
 

Sample Output
202
 

Source
2012 Asia Tianjin Regional Contest
 

Recommend
zhoujiaqi2010   |   We have carefully selected several similar problems for you:  5107 5106 5105 5104 5103 



用后缀数组处理,但是最后统计答案的办法需要深入思考,不过也不难。

目前先不写题解了,以后我时间总结一个后缀数组的所有类型题目。

//Hello. I'm Peter.#include<cstdio>#include<iostream>#include<sstream>#include<cstring>#include<string>#include<cmath>#include<cstdlib>#include<algorithm>#include<functional>#include<cctype>#include<ctime>#include<stack>#include<queue>#include<vector>#include<set>#include<map>using namespace std;typedef long long ll;typedef long double ld;#define peter cout<<"i am peter"<<endl#define input freopen("data.txt","r",stdin)#define randin srand((unsigned int)time(NULL))#define INT (0x3f3f3f3f)*2#define LL (0x3f3f3f3f3f3f3f3f)*2#define gsize(a) (int)a.size()#define len(a) (int)strlen(a)#define slen(s) (int)s.length()#define pb(a) push_back(a)#define clr(a) memset(a,0,sizeof(a))#define clr_minus1(a) memset(a,-1,sizeof(a))#define clr_INT(a) memset(a,INT,sizeof(a))#define clr_true(a) memset(a,true,sizeof(a))#define clr_false(a) memset(a,false,sizeof(a))#define clr_queue(q) while(!q.empty()) q.pop()#define clr_stack(s) while(!s.empty()) s.pop()#define rep(i, a, b) for (int i = a; i < b; i++)#define dep(i, a, b) for (int i = a; i > b; i--)#define repin(i, a, b) for (int i = a; i <= b; i++)#define depin(i, a, b) for (int i = a; i >= b; i--)#define pi 3.1415926535898#define eps 1e-6#define MOD 2012#define MAXN 200100#define N MAXN-10#define Mint wa[MAXN],wb[MAXN],wv[MAXN],wss[MAXN],sa[MAXN],r[MAXN];int cmp(int *r,int a,int b,int l){    return r[a]==r[b] && r[a+l]==r[b+l];}void Build_SuffixArray(int *r,int *sa,int n,int m){    int i,j,p,*x=wa,*y=wb,*t;    rep(i,0,m) wss[i]=0;    rep(i,0,n) wss[x[i]=r[i]]+=1;    rep(i,1,m) wss[i]+=wss[i-1];    depin(i,n-1,0) sa[--wss[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;        rep(i,0,n) if(sa[i]>=j) y[p++]=sa[i]-j;        rep(i,0,n) wv[i]=x[y[i]];        rep(i,0,m) wss[i]=0;        rep(i,0,n) wss[wv[i]]+=1;        rep(i,1,m) wss[i]+=wss[i-1];        depin(i,n-1,0) sa[--wss[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++;    }}int ranking[MAXN],height[MAXN];void Build_heightArray(int *r,int *sa,int n){    int i,j,k=0;    repin(i,1,n) ranking[sa[i]]=i;    for(i=0;i<n;height[ranking[i++]]=k){        for(k?k--:0,j=sa[ranking[i]-1];r[i+k]==r[j+k];k++);    }}int idx(char c){    return c-'0';}int tenpow[MAXN],tenpowsum[MAXN],symbol[MAXN],preans[MAXN],preanssum[MAXN],lenlimit[MAXN];int n,lens,numsym,ans;char s[MAXN];bool leggal(int i){//符合题意当且仅当 公共前缀长度不为0 且 s[i]处字符为'1'-'9'之间;    if(!height[i]) return false;    int p=sa[i];    if(!isdigit(s[p])) return false;    int t=idx(s[p]);    if(!t) return false;    else return true;}int Get_Number(char *s,int from,int to){//给定一个数字字符串S,O(1)求出从给定的S[L]..S[R]部分的所有前缀数字之和    int lent=to-from+1;    int res=preanssum[to]-preanssum[from-1];    res=(res%MOD+MOD)%MOD;    res-=preans[from-1]*(tenpowsum[lent]-1);    return res;}int main(){    //预处理y1(x)=10^x数组 以及 y1数组的前缀和数组    tenpow[0]=1;    repin(i,1,N){        tenpow[i]=tenpow[i-1]*10;        tenpow[i]%=MOD;    }    tenpowsum[0]=1;    repin(i,1,N){        tenpowsum[i]=tenpowsum[i-1]+tenpow[i];        tenpowsum[i]%=MOD;    }    while(~scanf("%d",&n))    {        //构造字符串:        s[0]='#';        lens=1;        numsym=0;        symbol[++numsym]=0;        repin(i,1,n){            scanf("%s",s+lens);            int lent=len(s+lens);            lens+=lent;            symbol[++numsym]=lens;            s[lens++]='#';        }        s[lens]='\0';        ans=0;        //构造每个串的长度限制数组:        depin(i,lens-1,0){            if(s[i]=='#') lenlimit[i]=0;            else{                lenlimit[i]=lenlimit[i+1]+1;            }        }        //构造每个串的前缀答案以及前缀和答案        repin(i,1,numsym-1){            preans[symbol[i]]=preans[symbol[i+1]]=0;            preanssum[symbol[i]]=preanssum[symbol[i+1]]=0;            int last=0,now=0;            rep(j,symbol[i]+1,symbol[i+1]){                now=last*10+idx(s[j]);                now%=MOD;                preans[j]=now;                preanssum[j]=preanssum[j-1]+now;                preanssum[j]%=MOD;                last=now;            }            //统计所有无前导0的数之和,记为ans (以后再减去多余部分)            rep(j,symbol[i]+1,symbol[i+1]){                if(!idx(s[j])) continue;                ans+=Get_Number(s,j,symbol[i+1]-1);                ans%=MOD;            }        }        //构造后缀数组和height数组        rep(i,0,lens){            r[i]=static_cast<int>(s[i]);        }        r[lens]=0;        Build_SuffixArray(r,sa,lens+1,'9'+1);        Build_heightArray(r,sa,lens);        //用后缀和height数组的性质将ans减去ans中多余的部分        repin(i,1,lens){            if(!leggal(i)) continue;            int from=sa[i];            int lent=min(height[i],lenlimit[from]);            int to=from+lent-1;            ans-=Get_Number(s,from,to);            ans=(ans%MOD+MOD)%MOD;        }        printf("%d\n",ans);    }}

0 0
原创粉丝点击