The Preliminary Contest for ICPC Asia Shanghai 2019 G: Substring (hash)

Word AA can match word BB if their corresponding starting and ending letters are same and the sets of letters in between are either the same or permutations of each other. For example "study'' can match "sdtuy'', "sduty'', "stduy''. But "study'' can not match "stuy'', "tsudy''.

Given a string SS containing lowercase letters, you need to answer MM queries, each query contains a word WW. Your task is to count the number of nonempty substrings of SS that matches word WW.

InputFile

The first line of the input gives the number of test cases, TT (T \leq 20T≤20).

The first line contains a string SS only contains lowercase. The length of the string will not be greater than 100,000100,000.

The second line contains one integer MM (1 \leq M \leq 200001≤M≤20000): the number of queries.

The following MM lines, each line contains a word WW only contains lowercase. The length of word WW won't more than 100,000100,000, and won't less than 22.The total length of strings in MM queries has the limit of 100,000100,000.

OutputFile

For each query, the output should contain a single number, on a single line: the number of nonempty substrings of SS that matches word WW.

樣例輸入複製

1
abccdefgdaaacdcdfegaada
4
gadaa
abccd
defg
aa

樣例輸出複製

2
1
2
3

題意: 給出一個原串S, 再有m次詢問, 每次詢問給出一個串T, 問串T在S中出現的次數, 只要首位相同,  中間的字母可以任意排列,詢問出現多少次。

思路: 因爲保證詢問的總長度不會超過1e5, 按長度劃分最壞情況, 1 + 2 + 3 + ... , 即sqrt(100000)次, 所以按詢問的長度來滾動hash

做法:開一個26 * 26的map, 前一位表示首字母, 後一維表示尾字母, 滾動hash求出中間的hash值,  再存入map中。

爲了避免內存超限, 再開一個map, 用來記錄詢問的串, 若該串是詢問的串, 答案再++。

hash用的素數隨機一組即可。

map貌似比unordered_map快樂一秒。

#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

#ifdef LOCAL
#define debug(x) cout << "[" __FUNCTION__ ": " #x " = " << (x) << "]\n"
#define TIME cout << "RuningTime: " << clock() << "ms\n", 0
#else
#define TIME 0
#endif
#define hash_ 1000000009
#define Continue(x) { x; continue; }
#define Break(x) { x; break; }
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
ll fpow(ll a, ll b, int mod) { ll res = 1; for (; b > 0; b >>= 1) { if (b & 1) res = res * a % mod; a = a * a % mod; } return res; }
map<ull, int>mp[26][26]; // ans
map<ull, int>hs[26][26]; // judge
int L[N]; // 枚舉的長度
char s[N];
int RL[N]; // 每次詢問的長度
bool vis[N]; 
char u[N];
ull re[N];  // 記錄每次詢問的信息
int b[N];  // 記錄每次詢問的首字母
int e[N];  // 尾字母
int one[26]; // 長度爲1的詢問單獨處理
ull pre[N] = { 2997022687, 3695434117, 2960269357, 3372990763, 2702977073, 3170671423, 1100043533, 4025511793, 4162159549, 2718605569, 1817382011, 2565699701, 2700004763, 3236418373, 1361985431, 3997357909, 1123926343, 1650465703, 3806403311, 2573034307, 2037529927, 2544053257, 1656504221, 1340707993, 1660464809, 4116524359 };
int main()
{
#ifdef LOCAL
	freopen("D:/input.txt", "r", stdin);
#endif
	int t;
	cin >> t;
	while (t--)
	{

		memset(one, 0, sizeof one);
		memset(vis, 0, sizeof vis);
		for (int i = 0; i < 26; i++)
			for (int j = 0; j < 26; j++)
				mp[i][j].clear(), hs[i][j].clear();
		scanf("%s", s + 1);
		int slen = strlen(s + 1);
		for (int i = 1; i <= slen; i++)
			one[s[i] - 'a']++;
		ll sum = 0;
		int m;
		int cnt = 0;
		cin >> m;
		for (int i = 1; i <= m; i++)
		{
			scanf("%s", u + 1);
			int len = strlen(u + 1);
			ull num = 0;
			RL[i] = len;
			b[i] = u[1] - 'a';
			e[i] = u[len] - 'a';
			for (int i = 2; i <= len - 1; i++)
				num += pre[u[i] - 'a'];
			re[i] = num;
			hs[b[i]][e[i]][num] = 1;
			if (vis[len] || len == 1)
				continue;
			vis[len] = 1;
			L[++cnt] = len;
		}
		for (int i = 1; i <= cnt; i++)
		{
			int len = L[i];
			ull num = 0;
			for (int j = 2; j <= len - 1; j++)
				num += pre[s[j] - 'a'];
			int u = s[1] - 'a';
			int v = s[len] - 'a';
			if (hs[u][v].find(num) != hs[u][v].end())
				mp[u][v][num]++;
			for (int i = len + 1; i <= slen; i++)
			{
				num -= pre[s[i - len + 1] - 'a'];
				num += pre[s[i - 1] - 'a'];
				u = s[i - len + 1] - 'a';
				v = s[i] - 'a';
				if (hs[u][v].find(num) != hs[u][v].end())
					mp[u][v][num]++;
			}
		}
		for (int i = 1; i <= m; i++)
		{
			if (RL[i] == 1)
				printf("%d\n", one[b[i]]);
			else
				printf("%d\n", mp[b[i]][e[i]][re[i]]);
		}
	}
	return TIME;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章