Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits
Description
Input
一行一个由大写字母A到L组成的字符串S。
Output
注意是输出子串的个数。
Sample Input
ABACABA
Sample Output
2
样例解释:BAC和CAB
Data Constraint
对于30%的数据,|S|<=100。
对于70%的数据,|S|<=1000。
对于100%的数据,1<=|S|<=1000000。
Source / Author: 常州高级中学NOIP2014夏令营 lintaojuren
反思:
比赛的时候就伪AC了, 自以为万无一失(打了两个程序, 一个暴力优化, 一个Ac版, 已经对了拍), 可两个程序都是错的, 错的一起错。
这个故事告诉我们对拍程序一定要是纯暴力程序。
思路 :
回想之前做过类似的题目, 对于要求两种元素在一段区间内数目相当, 我们把其中一种元素设为1, 另一个元素设为-1, 做一遍前缀和, 若i ~ j合法, 则pre[j] - pre[i - 1] = 0
可是现在我们有三种元素了。
那么把问题拆开 , 分别讨论ab和ac的相同段。
浅层思考, 对于结尾i, 把ab和ac相同段的开头列出, 若有相同, 则a=b=c。
可这样太慢了, 空间也不允许。
瓶颈在于不能利用前面已经获得的信息。
那么我们能不能对于结尾i, 找到距离i最近的j使其a = b = c, 然后利用j的信息呢?
可以。设cnt[i]为到i有多少a=b=c端点, cnt[i] = cnt[j] + 1, ans += cnt[i]。
时间复杂度比正解稍慢。
#include<bits/stdc++.h>
#define open(x) freopen(x".in", "r", stdin);freopen(x".out", "w", stdout)
#define mem(a, b) memset(a, b, sizeof(a))
#define mcy(a, b) memcpy(a, b, sizeof(a))
#define pf printf
#define sf scanf
#define fo(i, a, b) for(register int i = a; i <= b; ++i)
#define fown(i, a, b) for(register int i = a; i >= b; --i)
#define em(p, x) for(ll p=tail[x];p;p=e[p].fr)
#define ll long long
#define wt(a, c, d, s) fo(i, c, d) pf((s), a[i]); puts("")
#define rd(a, c, d) fo(i, c, d) in(a[i])
#define N 2000010
#define inf 2147483647
#define mod (ll)(1e9 + 7)
using namespace std;
template<class T>
T in(T &x) {
x=0;
char ch = getchar(); ll f = 0;
while(ch < '0' || ch > '9') f |= ch == '-', ch = getchar();
while(ch >= '0' && ch <= '9') x = (x<<1) + (x<<3) + ch - '0', ch = getchar();
x = f ? -x : x;
return x;
}
const ll fix = 1000001;
int n;
int lst1[N], lst2[N];
ll f1[N], f2[N], ans, pre1[N], pre2[N], cnt[N];
char s[N];
int main() {
open("gaint");
sf("%s\n", s + 1);
n = strlen(s + 1);
mem(lst1, 255), mem(lst2, 255);
f1[0] = f2[0] = fix;
lst1[f1[0]] = lst2[f2[0]] = 0;
pre1[0] = 0, pre2[0] = 0;
fo(i, 1, n) {
f1[i] = f1[i - 1], f2[i] = f2[i - 1];
if(s[i] == 'A')
f1[i]++, f2[i]++;
else if(s[i] == 'B')
f1[i]--;
else if(s[i] == 'C')
f2[i]--;
int p = lst1[f1[i]], q = lst2[f2[i]];
while(p >= 0 && q >= 0) {
if(p == q) break;
if(i - p > i - q) {
if(pre2[q] >=0)
q = pre2[q]; else break;
} else {if(pre1[p] >= 0)p = pre1[p]; else break;}
}
if(p == q && p >= 0) {
cnt[i] = cnt[p] + 1;
ans += cnt[i]; //add the ans before
}
pre1[i] = lst1[f1[i]], pre2[i] = lst2[f2[i]];
lst1[f1[i]] = i, lst2[f2[i]] = i;
}
printf("%lld\n", ans);
return 0;
}