標籤:style http color os io for ar line
題目連結:hdu 4909 String
題目大意:給定一個字串,由小寫字母組成,最多包含一個問號,問號可以表示空或者任意一個字母。問有多少個子串,字母出現的次數均為偶數。
解題思路:因為最多又26個字母,對應每個字母的奇數情況用1表示,偶數情況用0.將一個首碼串表示成一個位元。然後對於每種相同的數s,任選兩個即為一種可行子串(組合數學). 接著對於有問號的情況枚舉一下問號替代的字元,然後對於問號後面的狀態都要再加上一個該字元。這時計算個數時就要將前後分開討論了。
這題交C++,結果卡FST了,覺得很不科學,加排序複雜度才o(nlogn), 然後叫G++就過了,不過開別人好像是開了一個1<<26的數組計算個數,空間限的也太鬆了。
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef int ll;const int maxn = 20005;int n, num[maxn], s[maxn];char str[maxn];ll solve () { int tmp = num[0] = 0; for (int i = 1; i <= n; i++) { if (str[i] != ‘?‘) tmp ^= (1<<(str[i]-‘a‘)); s[i] = num[i] = tmp; } ll ret = 0; sort(num, num + n + 1); int mv = 0; while (mv <= n) { int p = 0; while (p + mv <= n && num[p+mv] == num[mv]) p++; ret += p * (p-1) / 2; mv += p; } return ret;}int a[maxn], b[maxn];ll handle (int x, int pos) { int A = pos, B = n + 1 - pos; for (int i = 0; i < pos; i++) a[i] = s[i]; for (int i = pos; i <= n; i++) b[i-pos] = s[i]^(1<<x); sort(a, a + A); sort(b, b + B); ll ret = 0; int mva = 0, mvb = 0; while (mva < A && mvb < B) { if (a[mva] > b[mvb]) mvb++; else if (a[mva] < b[mvb]) mva++; else { int i = 0, j = 0; while (i + mva < A && a[i+mva] == a[mva]) i++; while (j + mvb < B && b[j+mvb] == b[mvb]) j++; ret += i * j; mva += i; mvb += j; } } return ret;}int main () { int cas; scanf("%d", &cas); while (cas--) { scanf("%s", str+1); n = strlen(str+1); int pos = -1; for (int i = 1; i <= n; i++) { if (str[i] == ‘?‘) { pos = i; break; } } ll ans = solve(); if (pos != -1) { for (int i = 0; i + ‘a‘ <= ‘z‘; i++) ans += handle(i, pos); } printf("%d\n", ans); } return 0;}