D. A and B and Interesting Substrings
题意:给定26个小写字母的权值和一个字符串, 求出该字符串有多少个连续的子串,首尾相同, 并且除了首尾权值和为0。
思路:权值和为0说明子串的两个端点的前缀和相同, 先预处理出前缀和, 然后因为首尾要相同, 所以开26个map记录一个某个字符的前缀和的出现次数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <cstdlib>
using namespace std;
#define LL long long
#define inf 0x3f3f3f3f
#define eps 1e-8
#define ULL unsigned long long
#define mxn 100020
#define mxe 200020
#define mxnode 20020
#define mod 1000000007
#define vi vector<int>
#define pii pair<int, int>
#define vii vector<pii >
LL sum[mxn];
int a[30];
char s[mxn];
map<LL, int> b[30];
int main() {
while(1) {
for(int i = 0; i < 26; ++i) scanf("%d", &a[i]);
scanf("%s", s);
int n = strlen(s);
for(int i = 0; s[i]; ++i)
sum[i] = i == 0? a[s[i]-'a']: sum[i-1] + a[s[i]-'a'];
LL ans = 0;
for(int i = 0; i < 30; ++i) b[i].clear();
for(int i = 0; s[i]; ++i) {
int c = s[i] - 'a';
ans += b[c][sum[i-1]];
++b[c][sum[i]];
}
printf("%I64d\n", ans);
return 0;
}
return 0;
}
E. A and B and Lecture Rooms
题意:给定一棵树,和m个询问, 每个询问包括两个节点u和v,要求求出树上跟到u和v距离相同的节点的个数。
思路: 先求出u到v的距离dis, 可以用lca求, 如果dis==0的话, 答案就是n, 如果dis为奇数的话, 答案就是0.
最后,如果dis是偶数, 假设u的深度小于v的深度, 则求出v的dis/2级祖先w, 如果w和p相同的话, v的dis/2-1级祖先是x, u的dis/2-1级祖先是y, 答案就是n-sz[x]-sz[y],
如果w和p不相同的话, 答案就是sz[w] - sz[x].
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <cstdlib>
using namespace std;
#define LL long long
#define inf 0x3f3f3f3f
#define eps 1e-8
#define ULL unsigned long long
#define mxn 100020
#define mxe 200020
#define mxnode 20020
#define mod 1000000007
#define vi vector<int>
#define pii pair<int, int>
#define vii vector<pii >
int fst[mxn], nxt[mxe], to[mxe], e;
void init() {
memset(fst, -1, sizeof fst);
e = 0;
}
void add(int u, int v) {
to[e] = v, nxt[e] = fst[u], fst[u] = e++;
}
int n, m;
int sz[mxn];
int fa[22][mxn], dep[mxn];
void dfs(int u, int p, int d) {
sz[u] = 1;
dep[u] = d;
fa[0][u] = p;
for(int i = fst[u]; ~i; i = nxt[i]) {
int v = to[i];
if(v == p) continue;
dfs(v, u, d + 1);
sz[u] += sz[v];
}
}
void lcaInit() {
for(int k = 0; k < 21; ++k) {
for(int i = 1; i <= n; ++i) {
if(fa[k][i] != -1)
fa[k+1][i] = fa[k][fa[k][i]];
else
fa[k+1][i] = -1;
}
}
}
int lca(int u, int v) {
if(dep[u] > dep[v]) swap(u, v);
for(int k = 0; k < 22; ++k) {
if((dep[v] - dep[u]) >> k & 1)
v = fa[k][v];
}
if(u == v) return u;
for(int k = 21; k >= 0; --k) {
if(fa[k][u] != fa[k][v])
u = fa[k][u], v = fa[k][v];
}
return fa[0][u];
}
int kfa(int u, int k) {
int t = u;
for(int i = 0; i < 22; ++i) {
if(k >> i & 1)
u = fa[i][u];
}
return u;
}
int main() {
// freopen("tt.txt", "r", stdin);
while(scanf("%d", &n) != EOF) {
init();
for(int i = 1; i < n; ++i) {
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
dfs(1, -1, 0);
lcaInit();
scanf("%d", &m);
while(m--) {
int u, v;
scanf("%d%d", &u, &v);
int p = lca(u, v);
int dis = dep[u] + dep[v] - 2 * dep[p];
if(dis == 0) {
printf("%d\n", n);
continue;
}
if(dis % 2 == 1) {
puts("0");
continue;
}
if(dep[u] > dep[v]) swap(u, v);
int w = kfa(v, dis / 2);
int x = kfa(v, dis / 2 - 1);
int ans = 0;
if(w == p) {
int y = kfa(u, dis / 2 - 1);
ans = n - sz[x] - sz[y];
}
else {
ans = sz[w] - sz[x];
}
printf("%d\n", ans);
}
}
return 0;
}