字典树+Codeforces1285D

24 篇文章 0 订阅
5 篇文章 0 订阅

字典树模板

// 字典树模板
#include <bits/stdc++.h>
using namespace std;
struct{
    int num; // 如该节点是一个单词的结尾,记录单词的编号
    int next[26];
}trie[1000001];
string s[100001],a;
int tot,ans;
void Insert(string c,int k)
{
    // 插入一个字符串
    int i,t,len,p=1; // p表示标号
    len = c.length(); // 获取字符串的长度
    for(i = 0;i<len;i++) // 遍历
    {
        t=c[i]-'a'; // 字母的ascii
        if(trie[p].next[t] ==0) // 说明没有对应的节点
        {
            tot++; // 新增编号为tot的节点
            trie[p].next[t] = tot;// 记下p孩子节点的编号
            p = trie[p].next[t]; // p 指向新添加的节点,一步迭代
        }
        else
        {
            p=trie[p].next[t]; // 若已经存在,再令p指向它
        }
    }
    trie[p].num=k; // for循环执行完,证明第k个单词已经加入
}
int Find(string c) // 查找其中是否有字符串
{
    int i,t,len,p=1;
    len = c.length();
    for(i = 0;i<len;i++)
    {
        t = c[i]-'a';
        if(trie[p].next[t] ==0) return 0; // 没有要找的字符
        p=trie[p].next[t]; // 若存在继续查找
    }
    return trie[p].num;
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i]>>a;
        Insert(a,i);
    }
    for(int i=1;i<=m;i++)
    {
        cin>>a;
        ans=Find(a);
        if(ans)     cout<<s[ans]<<endl;
        else    cout<<"None"<<endl; // 没找到
    }
    return 0;
}

蓝书代码:主要是迭代部分

int trie[SIZE][26],tot=1;
void Insert(char * str)
{
    int len = strlen(str),p=1;
    for(int k=0;k<len;k++)
    {
        int ch = str[k]-'a';
        if(trie[p][ch]==0)  trie[p][ch] =++tot;
        p=trie[p][ch];
    }
    End[p] = true; // 该节点是终点
}
bool Search(char *str)
{
    int len = strlen(str),p=1;
    for(int k=0;k<len;k++)
    {
        p=trie[p][str[k]-'a'];
        if(p==0) return false;
    }
    return End[p];
}

CF1285D
题意:题意:给定n个数,要求你设定一个X,这个X与每个数异或后所得的结果最小,并且这个X要尽可能的大,输出这个异或出的最小的结果


#include <bits/stdc++.h>
using namespace std;
int cnt=1;
int tri[1<<21][2];
void Insert(int x)
{
    int p=1;
    for(int i=29;i>=0;i--) // 一共三十位
    {
        int ch =(x>>i)&1; // 取出二进制最高位
        if(tri[p][ch]==0) // p 是节点
        {
            tri[p][ch]=++cnt; // 统计个数
        }
        p=tri[p][ch];
    }
}
int solve(int mode,int now)
{
    if(mode==-1) // 小于0了返回0
        return 0;
    if(tri[now][0]==0)
        return solve(mode-1,tri[now][1]); // 选择最小ans值所以选择已有的
    else
    if(tri[now][1]==0)
        return solve(mode-1,tri[now][0]);
    else
        return ((1<<mode )+ min(solve(mode-1,tri[now][1]),solve(mode-1,tri[now][0]) )); // 因为要保证X是最大的,所以在最高有效位要留一个1才行
}
int main()
{
    int n,a;
    cin>>n;
    while(n--)
    {
        cin>>a;
        Insert(a);
    }
    cout<<solve(29,1)<<endl;
    //return "BT7274", NULL;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值