Codeforces Round #624 (Div. 3) C. Perform the Combo(前缀和)
You want to perform the combo on your opponent in one popular fighting game. The combo is the string ss consisting of nn lowercase Latin letters. To perform the combo, you have to press all buttons in the order they appear in ss . I.e. if s=s= "abca" then you have to press 'a', then 'b', 'c' and 'a' again.
You know that you will spend mm wrong tries to perform the combo and during the ii -th try you will make a mistake right after pipi -th button (1≤pi<n1≤pi<n ) (i.e. you will press first pipi buttons right and start performing the combo from the beginning). It is guaranteed that during the m+1m+1 -th try you press all buttons right and finally perform the combo.
I.e. if s=s= "abca", m=2m=2 and p=[1,3]p=[1,3] then the sequence of pressed buttons will be 'a' (here you're making a mistake and start performing the combo from the beginning), 'a', 'b', 'c', (here you're making a mistake and start performing the combo from the beginning), 'a' (note that at this point you will not perform the combo because of the mistake), 'b', 'c', 'a'.
Your task is to calculate for each button (letter) the number of times you'll press it.
You have to answer tt independent test cases.
The first line of the input contains one integer tt (1≤t≤1041≤t≤104 ) — the number of test cases.
Then tt test cases follow.
The first line of each test case contains two integers nn and mm (2≤n≤2⋅1052≤n≤2⋅105 , 1≤m≤2⋅1051≤m≤2⋅105 ) — the length of ss and the number of tries correspondingly.
The second line of each test case contains the string ss consisting of nn lowercase Latin letters.
The third line of each test case contains mm integers p1,p2,…,pmp1,p2,…,pm (1≤pi<n1≤pi<n ) — the number of characters pressed right during the ii -th try.
It is guaranteed that the sum of nn and the sum of mm both does not exceed 2⋅1052⋅105 (∑n≤2⋅105∑n≤2⋅105 , ∑m≤2⋅105∑m≤2⋅105 ).
It is guaranteed that the answer for each letter does not exceed 2⋅1092⋅109 .
For each test case, print the answer — 2626 integers: the number of times you press the button 'a', the number of times you press the button 'b', …… , the number of times you press the button 'z'.
3 4 2 abca 1 3 10 5 codeforces 2 8 3 2 9 26 10 qwertyuioplkjhgfdsazxcvbnm 20 10 1 2 3 5 10 5 9 4
4 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 4 5 3 0 0 0 0 0 0 0 0 9 0 0 3 1 0 0 0 0 0 0 0 2 1 1 2 9 2 2 2 5 2 2 2 1 1 5 4 11 8 2 7 5 1 10 1 5 2
大意就是给定一个字符串和一个序列p,第i次遍历字符串走到pi的位置就回到开头重新走,最后一次走完,问每个字母各出现了多少次。看数据范围直接暴力肯定不行。我一开始想的是从头往后对于每个位置求26个字母出现次数的前缀和,但这样会在第五个点T。看博客学习到了一个巧妙的解法,首先读入p数组的时候用一个和字符串等长的数组记录返回的位置,vis[p[i]]++,之后从后往前遍历。用一个变量cnt记录当前字母访问过的“次数”。
凡是遇到有标记的地方,直接cnt+=vis[i]。因为是从前往后遍历的,所以直接加上没有问题。然后是统计字幕出现次数的数组b[s[i]-'a']+=cnt;说明有多少趟经过这个字母了,直接统计到总的出现次数里即可。