HUST - 1616 给出字符串,求[l,r]内最大的子序列的hash值

You've got string S and m queries. Each query asks you to calculate the hash value for the lexicographically maximum subsequence of  substring S[l….r]. 
We'll call a non-empty string S[  p1p2...   pk] =   sp1sp2...   spk(1 ≤   p1 <   p2 < ... <  pk ≤ |  s|) a   subsequence of string   s =   s1s2...   s  |s|
String   x =   x1x2...   x  |x| is   lexicographically larger than string   y =  y1y2...   y  |y|, if either |  x| > |  y| and   x1 =   y1,   x2 =   y2, ... ,   x  |y| =   y  |y|, or exists such number   r (  r < |  x|,   r < |  y|), that   x1 =   y1,   x2 =   y2, ... ,   xr =  yr and   xr   + 1 >   yr   + 1. Characters in lines are compared like their ASCII codes. 
The hash value for string s of length n is 
Input
There are multiple cases, process to the  EOF. Each cases begins with a line contains a non-empty string   s, consisting only of lowercase English letters. The string's length doesn't exceed 10^6. The second line contains an integer m(1<=m<=10^6), indicate that there are m queries. Then the next m lines contains m queries, each line describe the query with two integer l and r.  
Output
Print the hash value of lexicographically maximum subsequence of string   sfor each query in separate line. 
Sample Input
abeced
2
1 3
1 6
kjihgfedcba
1
1 11
Sample Output
101
514298749
888634539

子序列是指:“abeced”的最大子序列为eed。

2traits:

1、每个区间的最优序列首字母一定是【该区间内最大值的首个出现位置】

2、对于每个区间[l,r]内的最优子序列,r这个点一定会被选进去

3、两个不同的点a,b,且a>b,往前的最优祖先一定一样

#include<bits/stdc++.h>
#define ll long long
#define inf 0x7fffffff
#define mod 1000000007
#define lowbit(x) (x) & (-x)  
using namespace std;
int pre[1000005];
int len[1000005];
ll sum[1000005];
ll g[1000005];
int id[30];
int w[1000005];
int c2[1000005];
char x[1000005];
int n;   

const int MAXN = 1000005;
int dp[MAXN][22];  
void makermq(int n,int b[])  
{  
    int i,j;  
    for(i=1;i<=n;i++)  
        dp[i][0]=b[i];  
    for(j=1;(1<<j)<=n;j++)  
        for(i=1;i+(1<<j)-1<=n;i++)  
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);  
}  
int rmq(int s,int v)  
{  
    int k=(int)(log((v-s+1)*1.0)/log(2.0));  
    return min(dp[s][k],dp[v-(1<<k)+1][k]);  
}  
  
void makeRmqIndex(int n,int b[]) //返回最大值对应的下标  
{  
    int i,j;  
    for(i=1;i<=n;i++)  
        dp[i][0]=i;  
    for(j=1;(1<<j)<=n;j++)  
        for(i=1;i+(1<<j)-1<=n;i++)  
            dp[i][j]=b[dp[i][j-1]] >= b[dp[i+(1<<(j-1))][j-1]]? dp[i][j-1]:dp[i+(1<<(j-1))][j-1];  
}  
int rmqIndex(int s,int v,int b[])  
{  
    int k=(int)(log((v-s+1)*1.0)/log(2.0));  
    return b[dp[s][k]]>=b[dp[v-(1<<k)+1][k]]? dp[s][k]:dp[v-(1<<k)+1][k];  
}  
int main(){
	g[0]=1;
	for(int i=1;i<=1000000;++i) g[i]=g[i-1]*1000007%mod;
	while(scanf("%s",x+1)!=EOF){
		memset(id,0,sizeof(id));
		n=strlen(x+1);
		for(int i=1;i<=n;++i){
			w[i]=x[i]-'a'+1;
			int maxx=0;
			for(int j=x[i]-'a';j<26;++j){
				maxx=max(maxx,id[j]);
			}
			pre[i]=maxx;
			len[i]=len[maxx]+1;
			id[x[i]-'a']=i;
			sum[i]=(sum[pre[i]]*1000007+x[i])%mod;
		}
		makeRmqIndex(n,w);
		int q;
		scanf("%d",&q);
		while(q--){
			int a,b;
			scanf("%d%d",&a,&b);
//			cout<<rmqIndex(a,b,w)<<endl;
			int ip=rmqIndex(a,b,w);
			printf("%lld\n",((sum[b]-sum[pre[ip]]*g[len[b]-len[pre[ip]]])%mod+mod)%mod);
		}
	}
} 


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值