题目:Link
暴力 - 前缀和
一道比较有趣的前缀和练习题
可以看出,题目有多次求 1 ∼ p i 1\sim p_i 1∼pi 上每个字母的数量。我们可以很轻松的用前缀和解决,只是需要多开一维记录字母
设 s [ i ] [ j ] s[i][j] s[i][j] 为在字符串前 i i i 位上,字典序为 j j j 的字母出现的次数
那么,对于每一次操作 p i p_i pi,我们只需求出所有 s [ p i ] [ 1 ∼ 26 ] s[p_i][1\sim 26] s[pi][1∼26],就可以了
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int Maxn=200000+10,inf=0x3f3f3f3f;
int s[Maxn][30],a[30];
int n,m;
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T=read();
while(T--)
{
n=read(),m=read();
char opt[Maxn];
scanf("%s",opt+1);
for(int i=1;i<=n;++i)
{
for(int j=0;j<26;++j) // 这里为了方便,下标从 0 开始
s[i][j]=s[i-1][j];
s[i][opt[i]-'a']++;
}
for(int i=1;i<=m;++i)
{
int x=read();
for(int j=0;j<26;++j)
a[j]+=s[x][j]; // 统计答案
}
for(int i=0;i<26;++i)
a[i]+=s[n][i];
for(int i=0;i<26;++i)
{
printf("%d ",a[i]);
a[i]=0;
}
putchar('\n');
}
return 0;
}
仔细观察可以发现,每组数据最后并不需要 memset \texttt{memset} memset,加了反而 TLE