B. The Fair Nut and Strings
题意:
在给定的字符串a和字符串b中找到最多k个字符串,使得不同的前缀字符串的数量最多。
分析:
建出trie树,给定的两个字符串就是trie树上的两条长度为n路径,那么就是在第n层的所有节点中,找到不大于k个点,(第n层的每个点向上到根的路径的路径上的字符组成一个长度为n字符串)。
两个第n层的节点一共会构成2n-lca个不同的前缀。所有可以根据这个贪心的选。每次尽量选已经走过的路径尽量少的路径。
从n往后枚举,计算长度为答案为i的可以选几个。
注意判断一下最后是否可以选择k个, 和已经选了的路径。
代码:
1 #include<cstdio>
2 #include<algorithm>
3 #include<cstring>
4 #include<cmath>
5 #include<iostream>
6 #include<cctype>
7 #include<set>
8 #include<map>
9 #include<queue>
10 #include<vector>
11 #define fi(s) freopen(s,"r",stdin)
12 #define fo(s) freopen(s,"w",stdout)
13 using namespace std;
14 typedef long long LL;
15
16 inline int read() {
17 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
18 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
19 }
20
21 const int N = 1000005;
22 char a[N], b[N];
23
24 int main () {
25 int n = read(); LL k; cin >> k;
26 scanf("%s%s", a + 1, b + 1);
27
28 LL now = 1, ans = 0, tot = 0;
29
30 for (int i = 1; i <= n; ++i) {
31 now = now * 2;
32 if (a[i] == 'b') now --;
33 if (b[i] == 'a') now --;
34 if (now >= k) { tot = k; break; }
35 }
36 if (tot == 0) tot = now;
37
38 now = 1;LL last = 0;
39 for (int i = 1; i <= n; ++i) {
40 now = 1ll * now * 2;
41 if (a[i] == 'b') now --;
42 if (b[i] == 'a') now --;
43 LL t = min(k, now); t = min(t, tot); t = min(t, now - last); t = max(t, 0ll);
44 ans += 1ll * t * (n - i + 1);
45 k -= t; tot -= t; last += t;
46 if ((!k) || (!tot)) break;
47 }
48 cout << ans;
49 return 0;
50 }
来源:oschina
链接:https://my.oschina.net/u/4408094/blog/3717946