题解 P4536 [CQOI2007]三角形
本题是一道找规律模拟的题目,做法有很多,找到规律后就不难。
看到很多题解都是反着推的,这里写一篇正推的题解。
题意
首先题面就有点晦涩难懂,题目建立在一个三角形的不断分割之中,这个看了图后是比较好理解的,题目中定义三角形所靠着的三角形为:
- 如果 B 不包含 A,且 A 的某一条完整的边是 B 的某条边的一部分,则我们说 A 靠在 B 的边上。
配合这张图就比较好理解了。
如图,对于
对于
至于每个三角形的编号,大概是递归式的,每一个字符代表着四个部分中的一个,其中4表示中间的三角形,显然只可能出现在末位,然后下一个字符就继续分四个部分。
到这里,题意已经很明确了。
思路
- 若
与 不相邻, 表示该三角形编号的一段后缀字符串,则 和 不相邻。 - 若
,则该三角形相邻的三角形仅为 时的 。 - 若
,则该三角形必有一个三角形为 时的 与之相邻,且所有与该三角形相邻的三角形序号最后一个字符都为 。 - 若
且 ,令 为 至 组成的字符串且 ,则 与 不相邻。
有了以上性质,我们可以得出以下结论:
- 若给定的三角形编号末位字符为
,根据性质 ,显然能求出与该三角形相邻的所有三角形。 - 若给定的三角形编号末位字符不为
,循环遍历每一个字符,根据性质 ,每次均插入同级的中央三角形,再根据性质 ,还需要把已不相邻的三角形删除,其正确性可以通过性质 证明。
上述思路貌似很复杂,但只要多画图,多找规律,其实也是很容易理解的。
接下来顺着结论模拟即可,我们扫了一遍字符串,每一个字符还要往回扫一遍删除,加上最后的排序,时间复杂度为
奉上代码。
#include <bits/stdc++.h>
using namespace std;
string s , t;
int n;
vector <string> ans;
void solve() {
if(s[n] == '4') {//特判末位为4
t = s.substr(0 , n + 1);
t[n] = '1';
ans.push_back(t);
t[n] = '2';
ans.push_back(t);
t[n] = '3';
ans.push_back(t);
cout << ans[0] << "\n" << ans[1] << "\n" << ans[2] << "\n";
return;
}
if(n == 1) {//因为后面从2开始循环,所以要特判1
cout << "T4" << "\n";
return;
}
ans.push_back("T4");//初始时T4是相邻的,要先插入
for(int i = 2; i <= n; i ++) {
for(int j = 1; j <= i - 1; j ++)
if(s[i - j] == s[i])//如上述性质4,删除已不相邻的三角形
for(int k = 0; k < ans.size(); k ++)
if(ans[k][i - j] == '4') //末位为4即为该级的中央三角形
ans.erase(ans.begin() + k);
t = s.substr(0 , i + 1);
t[i] = '4';
ans.push_back(t);
t[i] = s[i];
}
sort(ans.begin() , ans.end());//按字典序排序
for(int i = 0; i < ans.size(); i ++)
cout << ans[i] << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin >> s;
n = s.size() - 1;
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话