首页 > 其他分享 >11.19 CW 模拟赛 T2.终端命令

11.19 CW 模拟赛 T2.终端命令

时间:2024-11-20 14:41:03浏览次数:1  
标签:11.19 int T2 inq 字符串 Now CW NowTo dis

算法

考场上想到了一些, 但不多

容易想到把相关的字符串全部加到字典树中

然后操作只有两种嘛

  • 键盘输入
  • tab

显然的, 我们可以构造一颗 \(\rm{trie}\) 树, 对于键盘输入, 我们把 \(\rm{trie}\) 树上的点向其子节点连一条权值为 \(1\) 的点

对于按 tab 的情况, 分两种情况讨论

  • 到达末尾
    显然, 到达下一个字符串的末尾
  • 未到达末尾
    走到子树内编号最小的字符串的位置

先预处理好边, 然后就可以跑 \(\rm{bfs}\) 解决了

代码

主要问题在于下一个字符串的末尾和子树内编号最小的字符串的位置怎么找:

对于到达下一个字符串的末尾, 我们显然可以在每次标记末尾的时候记录一下, 最后一起加边即可

对于子树内编号最小的字符串, 在建立 \(\rm{trie}\) 树时, 我们就可以建好, 具体见代码

#include <bits/stdc++.h>
const int MAXN = 2e5 + 20;
const int MAXLEN = 1e6 + 20;
const int MAXM = 2e6 + 20;

int n;
std::string Aim;

std::string Folder[MAXN];
int EndNum[MAXN]; // 每个字符串的结尾点
int Past[MAXN]; // 路上经过的新点
int Past_Num = 0;

class Graph_Class
{
private:
    /*建立文件之间的边 (tab)*/
    void ADD1()
    {
        for (int i = 2; i <= n; i++)
            addedge(EndNum[i - 1], EndNum[i]);
            addedge(EndNum[n], EndNum[1]);
    }

    std::queue<int> Q;
    int dis[MAXLEN];
    bool inq[MAXLEN];
    void bfs()
    {
        Q.push(0);
        memset(dis, 0x3f, sizeof(dis));
        memset(inq, false, sizeof(inq));
        dis[0] = 0;
        inq[0] = true;
        while (!Q.empty())
        {
            int Now = Q.front();
            Q.pop();
            inq[Now] = false;
            if (Now == EndNum[n + 1]) {
                printf("%d",dis[Now]);
                exit(0);
            }

            for (int i = head[Now]; ~i; i = Edge[i].next) {
                int NowTo = Edge[i].to;
                if(dis[NowTo] > dis[Now] + 1) {
                    dis[NowTo] = std::min(dis[NowTo], dis[Now] + 1);
                    if(!inq[NowTo]) Q.push(NowTo), inq[NowTo] = true;
                }
            }
        }
    }

public:
    struct node
    {
        int to;
        int next;
    } Edge[MAXM << 1];
    int Edge_Cnt = 0;
    int head[MAXLEN];
    void head_init() { for (int i = 0; i <= 1e6 + 1; i++) head[i] = -1; }
    void addedge(int u, int v)
    {
        Edge[++Edge_Cnt].to = v, Edge[Edge_Cnt].next = head[u];
        head[u] = Edge_Cnt;
    }

    /*建图*/
    void solve()
    {
        ADD1();
    }

    /*求最短路*/
    void ShortestPath()
    {
        bfs();
    }
} Graph;

class Trie_Class
{
private:
    /*魔改 Trie 树*/
    struct node
    {
        int Son[26]; // 儿子 ('a' ~ 'z')
        int fa; // 父亲
        bool IsEnd = false; // 结尾 tag
    };

    void Insert(int Num)
    {
        int Now = 0;
        if(Num == 1)
            Past[++Past_Num] = Now;
        for (int i = 1; i < Folder[Num].length(); i++) {
            int ch = Folder[Num][i] - 'a';
            if (Trie[Now].Son[ch] == 0) Trie[Now].Son[ch] = ++Cnt, Trie[Cnt].fa = Now, Past[++Past_Num] = Cnt, Graph.addedge(Now, Cnt);

            Now = Trie[Now].Son[ch];
            if (i == Folder[Num].length() - 1) {
                Trie[Now].IsEnd = true;
                EndNum[Num] = Now;
            }
        }
        if (Num != n + 1)
            for (int i = 1; i <= Past_Num; i++) {
                Graph.addedge(Past[i], EndNum[Num]);
            }
    }

public:
    node Trie[MAXLEN];
    int Cnt = 0;

    /*建立 Trie 树*/
    void BuildTrie() {
        for (int i = 1; i <= n + 1; i++) Past_Num = 0, Insert(i);
    }
} Trie;

int main()
{
    scanf("%d", &n);
    std::cin >> Aim, Aim = " " + Aim;
    for (int i = 1; i <= n; i++) {
        std::cin >> Folder[i];
        Folder[i] = " " + Folder[i];
    }
    Folder[n + 1] = Aim;

    Graph.head_init();
    Trie.BuildTrie();

    Graph.solve();
    Graph.ShortestPath();

    return 0;
}

总结

最短操作不一定是 \(\rm{dp}\) , 也有可能建图跑最短路

利用输入建边是巧妙的, 利用好题中性质

标签:11.19,int,T2,inq,字符串,Now,CW,NowTo,dis
From: https://www.cnblogs.com/YzaCsp/p/18556818

相关文章

  • 2024.11.19随笔&联考总结
    联考看到T1就知道一定是简单计数题然后发现\(O(n)\)可以过于是就大概写了写式子就开写。写的过程中犯了一些低级错误,代码重构了一次才过。耽误的时间比较久。然后开T2,一眼有一个\(O(n^2)\)的dp。然后考虑优化,但是记录下标必须再带一个信息所以无论怎么优化都不能到\(O(n......
  • 富满 FM5013F SOT23-6 集成充电与电机驱动的控制芯片
    ......
  • P11290 【MX-S6-T2】「KDOI-11」飞船 题解
    注意到速度的形式是编号相乘,而又有\(x\in\{1,2,3,4\}\),所以最多\(\log_2y_i\)次速度就会达到\(10^9\)量级,而此时再加油最少需要\(1\)秒,所以再乘一定不优。直接dp,有\(f_{i,j,k}\)表示当前在第\(i\)个加油站,速度为\(2^j3^k\)的最短用时,后面的\(2^j3^k\)可以......
  • 11.19
    C++代码实现:cppincludeincludeinclude<unordered_map>usingnamespacestd;intmain(){intV,E;cin>>V>>E;//错误处理:顶点个数为0if(V==0){cout<<"error"<<endl;return0;}//错误处理:顶点个数为1,且边个数大于0if......
  • 11.19随笔
    这里是11.19随笔。题目留档:使用键盘输入数学表达式(含数字,四种运算符+、-、、/和小括号,其中运算数都是一位数(0~9)),将数学表达式转化成后缀表达式输出,利用后缀表达式求表达式的值并输出。输入格式:输入正确的表达式(可以有空格)后回车,得到后缀表达式和结果。输入括号缺失的表达式,输......
  • 11.19
    refuse用法搭配基本含义和用法‌:refuse的基本意思是“拒绝”,表示由于不情愿或不愿意而对某项要求或事物给予否定的回答或不接受某物或不肯做某事。refuse既可用作及物动词,也可用作不及物动词。用作及物动词时,可接名词、代词或动词不定式作宾语,有时也可接双宾语,其间接宾语可以转化......
  • 每日打卡 11.19 (2)
    includeinclude<string.h>include<windows.h>usingnamespacestd;structstudent{charname[10];intc,math,english;doubleaverage;};intmain(){intindex,n;structstudents[10],temp;cout<<"请输入学生人数:";cin>>......
  • 每日打卡 11.19
    includeinclude<string.h>include<windows.h>usingnamespacestd;structstudent{charname[10];intc,math,english;doubleaverage;};intmain(){intindex,n;structstudents[10],temp;cout<<"请输入学生人数:";cin>>n......
  • 2024.11.19 test
    A给定一个无限长序列的\(0\simn-1\)项,每项满足与\(n\)的差不超过\(1\)。之后的每一项满足\(a_i=\sum_{j=0}^{i-1}[a_j+j\gei]\)。\(q\)次询问第\(p\)个位置的值。\(p\le10^{15}\)。非常难的签到,考虑消去常数,将\(a_i\)全部减去\(n\),那么\(a_i=[a_{i-n-1}=1]-[a_......
  • [考试记录] 2024.11.19 noip模拟赛17
    T1选取字符串warning❗:本题解前缀含量过高。挺典的kmp。考虑到题目中的串都是一个串的前缀,那么所选出来的串,他们的前缀一定是最短的那个串。不妨直接枚举每一个前缀,也就是枚举每一个串,看他们是否可以作为前缀出现,hash即可,复杂度\(\mathcal{O}(N^2)\)。换个思路,考虑有多......