【CodeForces1202F】You Are Given Some Letters...

本文深入探讨了周期字符串匹配问题的高效算法实现,通过枚举周期并利用数学推导,提出了一个时间复杂度为O(sqrt(a+b))的解决方案。文章详细分析了如何判断一个周期是否合法,以及如何在满足条件的情况下计算所有可能的周期数量。

【题目链接】

【思路要点】

  • 枚举周期 p p p ,考虑如何判断其是否合法。
  • N = a + b , r = ⌊ N p ⌋ N=a+b,r=\lfloor\frac{N}{p}\rfloor N=a+b,r=pN ,那么最后一段有 N % r N\% r N%r 个字符,其中至少有 a % r a\% r a%r A A A b % r b\%r b%r B B B ,因此一个必要条件为 N % r ≥ a % r + b % r N\%r\geq a\%r+b\%r N%ra%r+b%r ,记 d e l t a = N % r − a % r − b % r delta=N\%r-a\%r-b\%r delta=N%ra%rb%r
  • 记在整段中的 A , B A,B A,B 的个数为 a 0 , b 0 a_0,b_0 a0,b0 ,在最后一段的 A , B A,B A,B 的个数为 a 1 , b 1 a_1,b_1 a1,b1 ,使得字符串存在长度为 p p p 的周期的充要条件是 a 0 ≥ a 1 , b 0 ≥ b 1 a_0\geq a_1,b_0\geq b_1 a0a1,b0b1 ,其必要性显然,并且不难构造。
  • 因此,我们需要 ⌊ a r ⌋ ≥ a % r , ⌊ b r ⌋ ≥ b % r \lfloor\frac{a}{r}\rfloor\geq a\%r,\lfloor\frac{b}{r}\rfloor\geq b\%r raa%r,rbb%r ,且 ⌊ ⌊ a r ⌋ − a % r r + 1 ⌋ + ⌊ ⌊ b r ⌋ − b % r r + 1 ⌋ ≥ d e l t a r \lfloor\frac{\lfloor\frac{a}{r}\rfloor- a\%r}{r+1}\rfloor+\lfloor\frac{\lfloor\frac{b}{r}\rfloor- b\%r}{r+1}\rfloor\geq \frac{delta}{r} r+1raa%r+r+1rbb%rrdelta ,注意这里 d e l t a delta delta 一定是 r r r 的倍数。
  • 至此,我们有了一个 O ( a + b ) O(a+b) O(a+b) 的做法。
  • 不难注意到多数条件中只出现了 r r r ,枚举 r r r ,则可以得到一个 p p p 的范围,据此计算答案即可。
  • 时间复杂度 O ( a + b ) O(\sqrt{a+b}) O(a+b )

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
void force() {
	int a, b; read(a), read(b);
	int n = a + b, ans = 0;
	for (int i = 1; i <= n; i++) {
		int r = n / i, delta = (n % i - (a % r + b % r)) / r;
		if (delta >= 0 && a / r >= a % r && b / r >= b % r && delta - (a / r - a % r) / (r + 1) - (b / r - b % r) / (r + 1) <= 0) ans++;
	}
	writeln(ans);
}
int main() {
	int a, b; read(a), read(b);
	int n = a + b, ans = 0;
	for (int i = 1, nxt; i <= n; i = nxt + 1) {
		int r = n / i; nxt = n / r;
		if (a / r >= a % r && b / r >= b % r) {
			int Min = (a % r + b % r);
			int Max = ((a / r - a % r) / (r + 1) + (b / r - b % r) / (r + 1)) * r + (a % r + b % r);
			int rMin = (n - Max) / r + ((n - Max) % r != 0);
			int rMax = (n - Min) / r;
			chkmax(rMin, i);
			chkmin(rMax, nxt);
			if (rMin <= rMax) ans += rMax - rMin + 1;
		}
	}
	writeln(ans);
	return 0;
}
关于 **Educational Codeforces Round 176 (Rated for Div. 2)** 的具体题目和解析尚未被提及于当前提供的引用内容中。然而,可以基于已有的参考资料以及常见的 Codeforces 题目风格来推测该场比赛可能涉及的内容。 通常情况下,Codeforces 比赛中的题目会覆盖算法基础、数据结构应用、动态规划等多个领域。以下是根据以往比赛的特点总结的一些常见题型及其解决思路: ### 常见题型分析 #### A 类题目:简单逻辑与模拟 这类题目一般考察基本编程能力,例如输入输出处理、条件判断等。 ```cpp // 示例代码展示如何通过简单的循环解决问题 #include <iostream> using namespace std; int main() { int n; cin >> n; string result = ""; for(int i = 0; i < n; ++i){ char c; cin >> c; if(c >= 'a' && c <= 'z') result += toupper(c); // 转大写字母 [^4] else result += tolower(c); } cout << result; } ``` #### B 类题目:数组操作或字符串匹配 此类问题往往需要一定的观察力去发现规律或者模式。 假设某道B类问题是给定一个整数序列并询问某些特定条件下子串的最大长度,则解决方案如下所示: ```cpp // 使用双指针法求解最大满足条件的连续区间大小 #include <vector> #include <algorithm> bool checkCondition(vector<int>& nums, int k) {...} int findMaxSubarraySize(const vector<int>& arr, int limit){ int l=0,r=-1,maxLen=0; while(r<(int)(arr.size()-1)){ r++; if(!checkCondition(arr,l,r)) continue; maxLen=max(maxLen,(r-l+1)); l++; } return maxLen; } ``` 对于更复杂的C至E级别难度较高的竞赛项目则需深入探讨高级技巧比如图论最短路径计算方法Dijkstra算法实现版本之一如下所列: ```cpp struct Edge{ long long v,w; }; const long long INF=(long long)1e18; void dijkstra(long long s,vector<vector<Edge>>& G,long long dist[]){ priority_queue<pair<long long ,long long>,vector<pair<long long ,long long>>,greater<>> pq; fill(dist,dist+n+1,INF); dist[s]=0;pq.emplace(0,s); while(pq.size()){ auto [d,u]=pq.top();pq.pop(); if(d>dist[u])continue; for(auto &[v,w]:G[u]){ if(w+d>=dist[v])continue; dist[v]=w+d; pq.emplace(dist[v],v); } } } ``` 尽管上述例子并非直接取自目标赛事(Educational Codeforces Round 176),但它们代表了相似类型的挑战可能会出现在实际比赛中遇到的情况之中[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值