CF 1083 B. The Fair Nut and Strings
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 }