Problem Description
You hava a non-empty string which consists of lowercase English letters and may contain at most one '?'. Let's choose non-empty substring G from S (it can be G = S). A substring of a string is a continuous subsequence of the string. if G contains '?' then '?' can be deleted or replaced by one of lowercase english letters. After that if each letter occurs even number of times in G then G is a good substring. Find number of all good substrings.
Input
The input consists of an integer T, followed by T lines, each containing a non-empty string. The length of the string doesn't exceed 20000.
[Technical Specification]
1 <= T <= 100
[Technical Specification]
1 <= T <= 100
Output
For each test case, print a single integer which is the number of good substrings of a given string.
Sample Input
3
abc?ca
aabbcc
aaaaa
Sample Output
7
6
6
题解:用二进制模拟前缀的奇偶状态,如果一个状态x经过添加了几个字母后回到状态x,那么这几个字母肯定符合good substrings。
感受:又get到了一个新技能。同时深深佩服想出这种方法的大佬。代码有参考网上的博客,不过花了1800多秒,手动实现的map只需要300多秒。
1 #pragma warning(disable:4996) 2 #include<map> 3 #include<string> 4 #include<cstdio> 5 #include<bitset> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 using namespace std; 10 typedef long long ll; 11 12 const int maxn = 2e4 + 4; 13 14 int T; 15 char s[maxn]; 16 17 int main() 18 { 19 scanf("%d", &T); while (T--) { 20 map<int, int> p; 21 scanf("%s", s); 22 int pos = -1, n = strlen(s); 23 for (int i = 0; i < n; i++) if (s[i] == '?') { pos = i; break; } 24 25 int ans = 0, x; 26 if (pos == -1) { 27 x = 0; p[0]++; 28 for (int i = 0; i < n; i++) { 29 x ^= 1 << (s[i] - 'a'); 30 ans += p[x]; 31 p[x]++; 32 } 33 printf("%d ", ans); 34 } 35 else { 36 x = 0; p[0]++; 37 for (int i = 0; i <= pos - 1; i++) { 38 x ^= 1 << (s[i] - 'a'); 39 ans += p[x]; 40 p[x]++; 41 } 42 p.clear(); 43 44 x = 0; p[0]++; 45 for (int i = pos + 1; i < n; i++) { 46 x ^= 1 << (s[i] - 'a'); 47 ans += p[x]; 48 p[x]++; 49 } 50 51 x = 0; 52 if (p.count(x)) ans += p[x]; 53 54 for (int i = 0; i < 26; i++) if (p.count(x ^ (1 << i))) ans += p[x ^ (1 << i)]; 55 56 for (int i = pos - 1; i >= 0; i--) { 57 x ^= 1 << (s[i] - 'a'); 58 if (p.count(x)) ans += p[x]; 59 for (int j = 0; j < 26; j++) if (p.count(x ^ (1 << j))) ans += p[x ^ (1 << j)]; 60 } 61 printf("%d ", ans); 62 } 63 } 64 return 0; 65 }
网上大佬手动实现的map,值得学习!!!!!!!!!!!!!
1 #pragma warning(disable:4996) 2 #include<map> 3 #include<string> 4 #include<cstdio> 5 #include<bitset> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 using namespace std; 10 typedef long long ll; 11 12 const int maxn = 2e4 + 4; 13 14 char s[maxn]; 15 16 struct m_map { 17 int tot, k[maxn], va[maxn]; 18 int head[maxn], next[maxn]; 19 m_map() { tot = 0; } 20 void clear() { 21 tot = 0; 22 memset(head, -1, sizeof(head)); 23 } 24 int &get(int v) { 25 int u = v % maxn; 26 for (int i = head[u]; i != -1; i = next[i]) if (k[i] == v) return va[i]; 27 k[tot] = v; va[tot] = 0; 28 next[tot] = head[u]; 29 head[u] = tot; 30 return va[tot++]; 31 } 32 int get2(int v) { 33 int u = v % maxn; 34 for (int i = head[u]; i != -1; i = next[i]) if (k[i] == v) return va[i]; 35 return 0; 36 } 37 }mp; 38 39 int Find(int p, int n) { 40 mp.clear(); 41 mp.get(0)++; //初始状态为0,想想"aa"这样的序列 42 int ans = 0, x = 0; 43 for (int i = p; i < n; i++) { 44 x ^= 1 << (s[i] - 'a'); 45 ans += mp.get2(x); 46 mp.get(x)++; 47 } 48 return ans; 49 } 50 51 int Find2(int p, int n) { 52 mp.clear(); 53 mp.get(0)++; //同理 54 int x = 0, ans = 0; 55 for (int i = 0; i < p; i++) { 56 x ^= 1 << (s[i] - 'a'); 57 mp.get(x)++; 58 } 59 ans += mp.get2(x); 60 for (int i = 0; i < 26; i++) ans += mp.get2(x ^ (1 << i)); 61 for (int i = p + 1; i < n; i++) { 62 x ^= 1 << (s[i] - 'a'); 63 ans += mp.get2(x); 64 for (int j = 0; j < 26; j++) ans += mp.get2(x ^ (1 << j)); 65 } 66 return ans; 67 } 68 69 int main() 70 { 71 int T; 72 scanf("%d", &T); 73 while (T--) { 74 scanf("%s", s); 75 int p = -1, n = strlen(s); 76 for (int i = 0; i < n; i++) if (s[i] == '?') p = i; 77 if (p == -1) printf("%d ", Find(0, n)); 78 else printf("%d ", Find(0, p) + Find(p + 1, n) + Find2(p, n)); 79 } 80 return 0; 81 }