题目链接:https://codeforces.com/contest/1029
A - Many Equal Substrings
题意:给一个长度为 \(n(1\leq n\leq50)\) 的字符串 \(t\) ,和一个正整数 \(k(1\leq k\leq50)\) ,要求构造一个最短的字符串 \(s\) ,使得 \(t\) 在 \(s\) 中恰好出现 \(k\) 次。
题解:看起来就像KMP算法,来个 \(O(n^3)\) 的做法就可以了,枚举重叠部分的两个开始位置,然后判断是否重叠,用此找出最长的重叠位置。但是直接复制一个前缀函数来用最简单。
在模板中提供的前缀函数是要求从0开始的,而 \(\pi(n)\) 即为整个字符串除去字符串本身的首尾重叠的最长长度。
注意留够空间。
int pi[3005]; void GetPrefixFunction(char *s, int sl) { pi[0] = 0, pi[1] = 0; for(int i = 1, k = 0; i < sl; ++i) { while(k && s[i] != s[k]) k = pi[k]; pi[i + 1] = (s[i] == s[k]) ? ++k : 0; } } char s[3005]; void test_case() { int n, k; scanf("%d%d%s", &n, &k, s); GetPrefixFunction(s, n); int p = pi[n]; int top = n; --k; while(k--) { for(int i = 0; i < n - p; ++i) { s[top] = s[top - (n - p)]; ++top; } } s[top] = '\0'; puts(s); }
B - Creating the Contest
题意:给一个长度为 \(n(1\leq n \leq 2\cdot 10^5)\) 的严格单调递增的数列,要求从中选出若干个数,使得除了最大的那个数外,每个数都存在一个比它大且不超过它的两倍的数。
题解:很显然最容易满足“比某个数大且不超过它的两倍”的是它的下一个数,意思是一旦断掉就要重新开始咯。
int a[200005]; void test_case() { int n; scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); int ans = 1, cur = 1; for(int i = 2; i <= n; ++i) { if(a[i] > a[i - 1] * 2) cur = 1; else { ++cur; ans = max(ans, cur); } } printf("%d\n", ans); }
C - Maximal Intersection
题意:给 \(n(2\leq n \leq 3\cdot 10^5)\) 条线段,移除恰好一条线段使得剩下的 \(n-1\) 条线段的交尽可能长。
题解:上次不是做过一个矩形版的吗?我还是用扫描线做的。这个直接维护线段的前缀交和后缀交就可以了。
int l[300005], r[300005]; int pl[300005], pr[300005]; int sl[300005], sr[300005]; void test_case() { int n; scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%d%d", &l[i], &r[i]); pl[0] = -INF, pr[0] = INF; for(int i = 1; i <= n; ++i) { pl[i] = max(pl[i - 1], l[i]); pr[i] = min(pr[i - 1], r[i]); } sl[n + 1] = -INF, sr[n + 1] = INF; for(int i = n; i >= 1; --i) { sl[i] = max(sl[i + 1], l[i]); sr[i] = min(sr[i + 1], r[i]); } int ans = 0; for(int i = 1; i <= n; ++i) { int L = max(pl[i - 1], sl[i + 1]); int R = min(pr[i - 1], sr[i + 1]); //printf("L=%d R=%d\n", L, R); ans = max(ans, R - L); } printf("%d\n", ans); }
D - Concatenated Multiples
题意:给 \(n(2\leq n \leq 2\cdot 10^5)\) 个正整数和一个正整数 \(k\) ,求有多少个有序数对 \((i,j) (i\neq j)\) 使得第 \(i\) 个数后面接上第 \(j\) 个数之后被 \(k\) 整除。
题解:处理出每个数模 \(k\) 的余数,分长度存储在map里面。然后枚举第一个数和第二个数的长度(第一个数左移的量),就可以在对应的map里面查到有多少个数满足题意了。最后把 \((i,i)\) 的情况去掉。
来源:https://www.cnblogs.com/KisekiPurin2019/p/12244534.html