由对于一个字符串使用多组数据想到使用前缀和的解法。
首先介绍下关于前缀和的内容
例题
Description
已知两个正整数a和b,求在a与b之间(包含a和b)的所有整数的十进制表示中1出现的次数。
Input
多组数据(不超过100000组),每组数据2个整数a,b.(1≤a,b≤1000000).
Output
每组数据的答案占一行。
Sample Input
1 10
10 100
2 1
Sample Output
2
20
1
因为多组测试样例针对1~1000000之间的数,考虑到直接暴力可能会超时,将每次的结果放置在一个A数组中,递推的公式为:
到这一个数字为止产生的1的个数 = 这一个数字之前的数字产生的1的个数 + 这一个数字新产生出来的1的个数
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int calculate(int num)
{
int sum = 0;
while(num)
{
if(num%10 == 1)
{
sum ++;
}
num = num/10;
}
return sum;
}
const int maxn = 1e6+1;
int A[maxn];
int main()
{
int a,b;
fill(A,A+maxn,0);
for(int i=1;i<=1e6;i++)
{
A[i] = A[i-1] +calculate(i);
//到这一个数字为止产生的1的个数 = 这一个数字之前的数字产生的1的个数 + 这一个数字新产生出来的1的个数
}
while(scanf("%d %d",&a,&b)!=EOF)
{
if(a>b)
{
swap(a,b);
}
printf("%d\n",A[b]-A[a-1]);
//a,b之间的数字含一的个数等于b含1的个数减去a-1含1的个数
}
return 0;
}
接下来介绍百度之星1002字串查询,思维方法与上面那题类似,也可以用前缀法来解答
数组A记录该字母在该字符位置之前产生的这个字母的个数
递推式子为:A[该字母][字符位置] = A[该字母][之前一个字符位置] + 该字符新产生的字符个数
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 10010;
int A[27][maxn];
string s;
int main()
{
int T;
scanf("%d",&T);
for(int u=0;u<T;u++)
{
int n,q;
fill(A[0],A[0]+27*maxn,0);
scanf("%d %d",&n,&q);
cin>>s;
for(int i=1;i<=s.length();i++)
{
for(int j=0;j<26;j++)
{
A[j][i] = A[j][i-1];
}
A[s[i-1]-'A'][i] ++;
}
for(int i=0;i<q;i++)
{
int a,b;
scanf("%d %d",&a,&b);
for(int j=0;j<26;j++)
{
if(A[j][b] - A[j][a-1]>0)
{
printf("%d\n",A[j][b] - A[j][a-1]);
break;
}
}
}
}
return 0;
}