题解 P4536 [CQOI2007]三角形

原题

本题是一道找规律模拟的题目,做法有很多,找到规律后就不难。

看到很多题解都是反着推的,这里写一篇正推的题解。

题意

首先题面就有点晦涩难懂,题目建立在一个三角形的不断分割之中,这个看了图后是比较好理解的,题目中定义三角形所靠着的三角形为:

  • 如果 B 不包含 A,且 A 的某一条完整的边是 B 的某条边的一部分,则我们说 A 靠在 B 的边上。

配合这张图就比较好理解了。

如图,对于 T122,它与 T124T4 相邻,但它不与 T123T21 相邻。

对于 T31,虽然它有边是 T3 的边的一部分,但因为 T3 包含 T31,所以 T31 不与 T3 相邻。

至于每个三角形的编号,大概是递归式的,每一个字符代表着四个部分中的一个,其中4表示中间的三角形,显然只可能出现在末位,然后下一个字符就继续分四个部分。

到这里,题意已经很明确了。

思路

S 表示三角形编号的字符串,len 表示字符串 S 的长度,观察后我们发现该分形有以下性质:

  1. SS 不相邻,t 表示该三角形编号的一段后缀字符串,则 S+tS 不相邻。
  2. Slen=4,则该三角形相邻的三角形仅为 Slen{1,2,3} 时的 S
  3. Slen4,则该三角形必有一个三角形为 Slen=4 时的 S 与之相邻,且所有与该三角形相邻的三角形序号最后一个字符都为 4
  4. Slen{1,2,3}Sleni=Slen (i[1,len1]),令 SS1Sleni1 组成的字符串且 Sleni=4,则 SS 不相邻。

有了以上性质,我们可以得出以下结论:

  • 若给定的三角形编号末位字符为 4,根据性质 2,显然能求出与该三角形相邻的所有三角形。
  • 若给定的三角形编号末位字符不为 4,循环遍历每一个字符,根据性质 3,每次均插入同级的中央三角形,再根据性质 4,还需要把已不相邻的三角形删除,其正确性可以通过性质 1 证明。

上述思路貌似很复杂,但只要多画图,多找规律,其实也是很容易理解的。

接下来顺着结论模拟即可,我们扫了一遍字符串,每一个字符还要往回扫一遍删除,加上最后的排序,时间复杂度为 O(n2+nlogn)

奉上代码。

#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;
}
posted @   Terac  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示