#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <queue>
using namespace std;
typedef long long LL;
#define M 300011
#define P 3
#define PI pair<int, int>
#define MP make_pair
#define VI vector<int>
#define PB push_back
int n;
char word[M];
int last[P], lCount[P];
map<PI, int> diff;
vector<int> positions[3][2*M+1];
int cursor[3][2*M+1];
int main() {
scanf("%s", word);
n=strlen(word);
LL result=0;
last[0]=last[1]=last[2]=-1;
positions[0][M].PB(-1);
positions[1][M].PB(-1);
positions[2][M].PB(-1);
diff[MP(0, 0)]=1;
for (int i=0; i<n; i++) {
if (word[i]<'a' || word[i]>'c') {
printf("INVALID word: word[%d]=%c\n", i, word[i]);
return 1;
}
int curr=word[i]-'a';
last[curr]=i;
lCount[curr]++;
// Words finishing at this point consisting of exactly one letter.
int prev=-1;
for (int a=0; a<P; a++)
if (a!=curr && (prev==-1 || last[a]>last[prev])) prev=a;
result+=(LL)(i-last[prev]);
int other=3-curr-prev;
// Words finishing at this point consisting of exactly two letters.
if (last[prev]!=-1) {
// We know that those letters are curr and prev.
// We look for positions that are:
// - greater or equal than last[other]
// - that have equal difference in count of curr and prev
int idx=curr+prev-1;
int a=min(curr, prev), b=max(curr, prev);
int d=lCount[a]-lCount[b];
while (cursor[idx][d+M]<positions[idx][d+M].size()) {
int x=positions[idx][d+M][cursor[idx][d+M]];
if (x<last[other]) cursor[idx][d+M]++;
else break;
}
result+=(LL)(positions[idx][d+M].size()-cursor[idx][d+M]);
}
positions[0][lCount[0]-lCount[1]+M].PB(i);
positions[1][lCount[0]-lCount[2]+M].PB(i);
positions[2][lCount[1]-lCount[2]+M].PB(i);
// Words finishing at this point consisting of exactly three letters.
PI currDiff=MP(lCount[0]-lCount[1], lCount[0]-lCount[2]);
result+=(LL)diff[currDiff];
diff[currDiff]++;
}
printf("%lld\n", result);
return 0;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #include <cstdio> #include <algorithm> #include <vector> #include <cstring> #include <map> #include <queue> using namespace std; typedef long long LL; #define M 300011 #define P 3 #define PI pair<int, int> #define MP make_pair #define VI vector<int> #define PB push_back int n; char word[M]; int last[P], lCount[P]; map<PI, int> diff; vector<int> positions[3][2*M+1]; int cursor[3][2*M+1]; int main() { scanf("%s", word); n=strlen(word); LL result=0; last[0]=last[1]=last[2]=-1; positions[0][M].PB(-1); positions[1][M].PB(-1); positions[2][M].PB(-1); diff[MP(0, 0)]=1; for (int i=0; i<n; i++) { if (word[i]<'a' || word[i]>'c') { printf("INVALID word: word[%d]=%c\n", i, word[i]); return 1; } int curr=word[i]-'a'; last[curr]=i; lCount[curr]++; // Words finishing at this point consisting of exactly one letter. int prev=-1; for (int a=0; a<P; a++) if (a!=curr && (prev==-1 || last[a]>last[prev])) prev=a; result+=(LL)(i-last[prev]); int other=3-curr-prev; // Words finishing at this point consisting of exactly two letters. if (last[prev]!=-1) { // We know that those letters are curr and prev. // We look for positions that are: // - greater or equal than last[other] // - that have equal difference in count of curr and prev int idx=curr+prev-1; int a=min(curr, prev), b=max(curr, prev); int d=lCount[a]-lCount[b]; while (cursor[idx][d+M]<positions[idx][d+M].size()) { int x=positions[idx][d+M][cursor[idx][d+M]]; if (x<last[other]) cursor[idx][d+M]++; else break; } result+=(LL)(positions[idx][d+M].size()-cursor[idx][d+M]); } positions[0][lCount[0]-lCount[1]+M].PB(i); positions[1][lCount[0]-lCount[2]+M].PB(i); positions[2][lCount[1]-lCount[2]+M].PB(i); // Words finishing at this point consisting of exactly three letters. PI currDiff=MP(lCount[0]-lCount[1], lCount[0]-lCount[2]); result+=(LL)diff[currDiff]; diff[currDiff]++; } printf("%lld\n", result); return 0; } |
English