题目连接: 老师永远不知道在上网课的学生都在干嘛
给出一个字符串,再给出m个子串,求子串和原串个字母出现的次数
这题不是很难,最难的是好久不写把输出函数给忘了
最朴素的算法就是把每个子串都走一遍累加,但是时间和空间复杂都太高,所以就想,能不能统计每个位置出现的次数。
每个子串结束之前必然要计数一次,所以记录每个子串结束的位置,倒序遍历原串,若当前位置有子串结束,那么之前的位置都要计数一次,所以出现次数+1.
要注意的是这里不只有子串,还有原串,因此原串的最后一个位置初始值为1
#pragma GCC diagnostic error "-std=c++11"
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return
#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
template<class T> void _deb(const char *name,T val){
cout<<name<<val<<endl;
}
const int maxn=2e5+5;
int T;
int n,m;
char store[maxn]; %原串
int mistake[maxn]; %错误位置
int times[maxn]; %每个位置的出现次数
int statistics[26]; %每个字母出现的总次数
int main(){
scanf("%d",&T);
while(T--){
mem(statistics,0);
mem(times,0);
scanf("%d%d",&n,&m);
scanf("%s", store+1);
rep(i,0,m){
scanf("%d",&mistake[i]);
}
sort(mistake,mistake+m);
times[n]=1;
drep(i,m-1,0){
times[mistake[i]]+=1;
}
drep(i,n,1){
int pos = store[i]-'a';
times[i] += times[i+1];
statistics[pos] += times[i];
}
rep(i,0,26){
printf("%d ",statistics[i]);
}
printf("\n");
}
re 0;
}