题目分析
从没有用过倍增,但是感觉很巧妙,让我感受到了算法的魅力,主要就是一个思想dp[i][j]表示i前面(1 << j)对应的字母的位置,这样写过ST表的同学应该就差不多应该懂了, dp[i][j]=dp[dp[i][j−1]][j−1] ,这样很容易就推出来了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5+100;
char s[maxn];
int a[maxn], p[maxn], c[5];
int dp[maxn][25];
int main(){
while(scanf("%s", s+1) != EOF){
int len = strlen(s+1);
for(int i = 1; i<= len; i++){
if(s[i] == 'e') a[i] = 0;
else if(s[i] == 'a') a[i] = 1;
else if(s[i] == 's') a[i] = 2;
else if(s[i] == 'y') a[i] = 3;
}
memset(dp, 0, sizeof(dp));
memset(c, 0, sizeof(c));
for(int i = 1; i <= len; i++){ //找到每一个数前一个对应的字母的位置
int pre = (a[i] + 3)%4;
dp[i][0] = c[pre];
c[a[i]] = i;
p[i] = c[3];
}
for(int i = 1; i <= 20; i++)
for(int j = 1; j <= len; j++) //无敌倍增!!!
dp[j][i] = dp[dp[j][i-1]][i-1];
int m, l, r;
scanf("%d", &m);
while(m--){
scanf("%d%d", &l, &r);
int ans = 1, v = p[r]; //ans之所以等于1是因为当前v所在的位置是y
for(int i = 20; i >= 0; i--) //这里很容易懂大家可以一下
if(dp[v][i] >= l){
ans += (1<<i);
v = dp[v][i];
}
printf("%d\n", ans/4);
}
}
return 0;
}