题意
求一个字符串有多少个不同的子串,要求这些子串都包含至少一次x字符。
思路
如果不考虑包含x字符的话,求不同子串个数是一个后缀数组经典问题(spoj 694)。考虑那个问题的做法:∑leni=1len−sa[i]−lcp[i],len-sa[i]就是sa[i]开头的串的个数,再减去sa[i-1]时减过的lcp[i],累加起来就是答案了。然后这题直接只需要记录一下对每个下标i的后面最近出现x的位置nxt[i]是多少。然后在计算子串个数的时候不要计算nxt[i]之前的串就可以了。
我用之前那个题的代码改了一下结果TLE了。后来发现是板子的问题,挑战程序设计竞赛的板子使用的快排(出题人竟然卡这个。。话说这个板子A了很多题了这是第一次被卡= =
然后换成大白书上的过了。
代码
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define LL long long
#define Lowbit(x) ((x)&(-x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1|1
#define MP(a, b) make_pair(a, b)
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const int maxn = 1e5 + 10;
const double eps = 1e-8;
const double PI = acos(-1.0);
typedef pair<int, int> pii;
//int temp[maxn], lcp[maxn];
char x[2];
char str[maxn];
int nxt[maxn];
int sa[maxn], rk[maxn], height[maxn];
int c[maxn], t[2][maxn], s[maxn];
void build(int n, int m) {
int i, k, p, *x = t[0], *y = t[1];
memset(c, 0, m << 2);
for(i = 0; i < n; ++i) ++c[x[i] = s[i]];
for(i = 1; i < m; ++i) c[i] += c[i - 1];
for(i = n - 1; i >= 0; --i) sa[--c[x[i]]] = i;
for(k = 1; k <= n; k <<= 1) {
p = 0;
for(i = n - k; i < n; ++i) y[p++] = i;
for(i = 0; i < n; ++i) if(sa[i] >= k) y[p++] = sa[i] - k;
memset(c, 0, m << 2);
for(i = 0; i < n; ++i) ++c[x[y[i]]];
for(i = 1; i < m; ++i) c[i] += c[i - 1];
for(i = n - 1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];
swap(x, y); p = 1; x[sa[0]] = 0;
for(i = 1; i < n; ++i)
x[sa[i]] = (y[sa[i - 1]] == y[sa[i]] &&
y[sa[i - 1] + k] == y[sa[i] + k]) ? p - 1 : p++;
if(p >= n) break; m = p;
}
for(i = 0; i < n; ++i) rk[sa[i]] = i;
for(i = 0, k = 0; i < n; ++i) {
if(k) k--;
if(!rk[i]) continue;
int j = sa[rk[i] - 1];
while(s[i + k] == s[j + k]) k++;
height[rk[i]] = k;
}
}
//int compare_sa(int i, int j)
//{
// if (rk[i] != rk[j]) return rk[i] < rk[j];
// else
// {
// int ri = i + k <= n ? rk[i+k] : -1;
// int rj = j + k <= n ? rk[j+k] : -1;
// return ri < rj;
// }
//}
//
//void construct_sa(char *s, int *sa)
//{
// for (int i = 0; i <= n; i++)
// {
// sa[i] = i;
// rk[i] = i < n ? s[i] : -1;
// }
// for (k = 1; k <= n; k *= 2)
// {
// sort(sa, sa + n + 1, compare_sa);
// temp[s[0]] = 0;
// for (int i = 1; i <= n; i++)
// temp[sa[i]] = temp[sa[i-1]] + (compare_sa(sa[i-1], sa[i]) ? 1 : 0);
// for (int i = 0; i <= n; i++)
// rk[i] = temp[i];
// }
//}
//
//void construct_lcp(char *s, int *sa, int *lcp)
//{
// for (int i = 0; i <= n; i++) rk[sa[i]] = i;
// int h = 0;
// lcp[0] = 0;
// for (int i = 0; i < n; i++)
// {
// int j = sa[rk[i] - 1];
// if (h > 0) h--;
// for (; j + h < n && i + h < n; h++)
// if (s[j+h] != s[i+h]) break;
// lcp[rk[i] - 1] = h;
// }
//}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d", &T);
for (int ncase = 1; ncase <= T; ncase++)
{
scanf("%s%s", x, str);
int n = strlen(str);
for (int i = 0; i < n; i++) s[i] = str[i] - 'a' + 1;
s[n] = 0;
build(n + 1, 30);
nxt[n] = n;
for (int i = n - 1; i >= 0; i--)
{
nxt[i] = nxt[i+1];
if (str[i] == x[0]) nxt[i] = i;
}
LL ans = 0;
for (int i = 1; i <= n; i++)
{
//printf("%d %d %d %d\n", i, sa[i], height[i], nxt[sa[i]]);
ans += n - max(sa[i] + height[i], nxt[sa[i]]);
}
printf("Case #%d: %lld\n", ncase, ans);
}
return 0;
}