牛客多校第三场 H 题题解

Hacker

https://ac.nowcoder.com/acm/contest/33188/H

题意:给定长度为 nn 的模式串 SS,和长度为 mm 的权值数组 {wi}\{w_i\}。对于一个长度为 mm 的串,wiw_i 表示使用该串上第 ii 个字符与 SS 匹配可以获得 wiw_i 的权值。kk 次询问一个长度为 mm 的串 TTSS 的最大权值公共子串。n,m,k1×105,mq1×106n ,m,k\leq 1\times 10^5,mq\leq 1\times10^6

解法:对 SS 建立 SAM,然后对于每次询问都可以将 TT 串拉上去跑,对于 TT 串,每匹配一个字符,就可以通过 SAM 知道当前匹配了多长的字符串。此题为 SAM 经典应用之最长公共子串问题。因而问题转化成为了对于每个右端点 rr,有一个左边界 ll,然后问处于某个区间的最大连续子段和。维护 ww 的前缀和,利用区间查询最小值的线段树即可通过。复杂度 O(n+nlogn)\mathcal O(n+n\log n)

#include <bits/stdc++.h>
using namespace std;
long long inf = 0x3f3f3f3f3f3f3f3fll;
class segment_tree
{
    int n;
    vector<long long> minimum;
    long long query(int place, int left, int right, int start, int end)
    {
        if (start <= left && right <= end)
            return minimum[place];
        long long ans = inf;
        int mid = (left + right) >> 1;
        if (start <= mid)
            ans = min(ans, query(place << 1, left, mid, start, end));
        if (end > mid)
            ans = min(ans, query(place << 1 | 1, mid + 1, right, start, end));
        return ans;
    }

public:
    void set(int n, vector<long long> &w)
    {
        this->n = n;
        minimum.resize(4 * n + 10);
        function<void(int, int, int)> build = [&](int place, int left, int right)
        {
            if (left == right)
            {
                minimum[place] = w[left];
                return;
            }
            int mid = (left + right) >> 1;
            build(place << 1, left, mid);
            build(place << 1 | 1, mid + 1, right);
            minimum[place] = min(minimum[place << 1], minimum[place << 1 | 1]);
        };
        build(1, 0, n);
    }
    long long query(int l, int r)
    {
        return query(1, 0, n, l, r);
    }
} tr;
vector<long long> pre;
class SAM
{
    const int shift = 97;
    struct node
    {
        int ch[26];
        int len;
        int father;
        long long cnt;
        node()
        {
            memset(ch, 0, sizeof(ch));
            len = father = cnt = 0;
        }
    } NIL;
    vector<node> t;
    int last, ind;
    void insert(int c)
    {
        int p = last;
        int np = last = ++ind;
        t.push_back(NIL);
        t[np].len = t[p].len + 1;
        t[np].cnt = 1;
        for (; p && !t[p].ch[c]; p = t[p].father)
            t[p].ch[c] = np;
        if(!p)
            t[np].father = 1;
        else
        {
            int q = t[p].ch[c];
            if (t[p].len + 1 == t[q].len)
                t[np].father = q;
            else
            {
                int nq = ++ind;
                t.push_back(t[q]);
                t[nq].cnt = 0;
                t[nq].len = t[p].len + 1;
                t[q].father = t[np].father = nq;
                for (; p && t[p].ch[c] == q; p = t[p].father)
                    t[p].ch[c] = nq;
            }
        }
    }
 
public:
    SAM(string s)
    {
        last = ind = 1;
        t.push_back(NIL);
        t.push_back(NIL);
        for (auto i : s)
            insert(i - shift);
    }
    long long query(string &s)
    {
        int place = 1, len = 0, n = s.length();
        long long ans = 0;
        for (int i = 0; i < n;i++)
        {
            while (place > 1 && !t[place].ch[s[i] - shift])
            {
                place = t[place].father;
                len = t[place].len;
            }
            if (!t[place].ch[s[i] - shift])
                continue;
            place = t[place].ch[s[i] - shift];
            len++;
            ans = max(ans, pre[i + 1] - tr.query(i + 1 - len, i + 1));
        }
        return ans;
    }
};
int main()
{
    cin.tie(0)->sync_with_stdio(0);
    cin.exceptions(cin.failbit);
    cin.tie(NULL);
    cout.tie(NULL);
    int n, m, k;
    long long x;
    cin >> n >> m >> k;
    pre.resize(m + 1);
    string s, t;
    cin >> s;
    SAM solve(s);
    for (int i = 1; i <= m;i++)
    {
        cin >> x;
        pre[i] = pre[i - 1] + x;
    }
    tr.set(n, pre);
    for (int i = 1; i <= k;i++)
    {
        cin >> t;
        cout << solve.query(t) << "\n";
    }
    return 0;
}
全部评论

相关推荐

03-19 18:27
已编辑
门头沟学院 C++
26学院本太难了,很多公司机筛就给我刷了。机会都难拿到如果是简历存在问题也欢迎拷打————————————————————分割线——————————————————————2026.3.4更新:发完贴之后,时不时投递又收到了不少的笔试/面试邀请。主要是之前投递简历出去之后基本上都是沉默状态,年后好转了不少timeline:2026.01.21&nbsp;文远知行笔试,半年多没刷算法题&nbsp;-&gt;挂&nbsp;(后续HR说春招可以重新安排笔试)2026.2.4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;小鹏汇天&nbsp;技术一面,第二周收到结果&nbsp;-&gt;挂2026.2.12&nbsp;&nbsp;&nbsp;大众Cariad代招&nbsp;技术二面&nbsp;-&gt;Offer2026.2.28&nbsp;&nbsp;&nbsp;多益网络技术面试,由于风评太差,一直在犹豫要不要接面试&nbsp;-&gt;推迟-----------分割线-----------2026.3&nbsp;月前的某一天,临时去电网报名了二批计算机岗位的笔试2026.3.6&nbsp;从上家公司实习离职,氛围最好的一家公司,leader&nbsp;说可以帮忙转正,但是流程太长,而且我们部门据说只有一个&nbsp;hc,更想要研究生,我很有可能是会被签外包公司在这里干活,就离职了。2026.3.9&nbsp;入职新公司,大众Cariad&nbsp;以外部公司的身份进组,项目组签了三年,后续三年应该都可以在这里呆,不知道有没有希望原地跳槽。2026.3.10&nbsp;电网考试居然说我通过资格审查了,短信约我去参加资格审查,请假一天,买了&nbsp;12&nbsp;号晚上的机票回成都2026.3.15&nbsp;参加国家电网三新计算机类的笔试2026.3.17&nbsp;电网出成绩了,感觉很低。觉得已经🈚️了2026.3.18&nbsp;收到电网面试通知,通知&nbsp;3.22-3.25&nbsp;这个时间去面试,我的岗位只招&nbsp;1&nbsp;个人。据说面试只有&nbsp;2-3&nbsp;人,不知道能不能成功
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
正在热议
更多
# 春招至今,你的战绩如何? #
12299次浏览 109人参与
# 你的实习产出是真实的还是包装的? #
2126次浏览 43人参与
# 巨人网络春招 #
11411次浏览 223人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
7794次浏览 43人参与
# 简历第一个项目做什么 #
31858次浏览 345人参与
# 重来一次,我还会选择这个专业吗 #
433688次浏览 3926人参与
# MiniMax求职进展汇总 #
24353次浏览 310人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
187380次浏览 1122人参与
# 牛客AI文生图 #
21472次浏览 238人参与
# 不考虑薪资和职业,你最想做什么工作呢? #
152618次浏览 888人参与
# 研究所笔面经互助 #
119003次浏览 577人参与
# 简历中的项目经历要怎么写? #
310603次浏览 4231人参与
# AI时代,哪些岗位最容易被淘汰 #
64131次浏览 839人参与
# 面试紧张时你会有什么表现? #
30537次浏览 188人参与
# 你今年的平均薪资是多少? #
213317次浏览 1039人参与
# 你怎么看待AI面试 #
180372次浏览 1269人参与
# 高学历就一定能找到好工作吗? #
64353次浏览 620人参与
# 你最满意的offer薪资是哪家公司? #
76715次浏览 374人参与
# 我的求职精神状态 #
448253次浏览 3129人参与
# 正在春招的你,也参与了去年秋招吗? #
363827次浏览 2638人参与
# 腾讯音乐求职进展汇总 #
160736次浏览 1114人参与
# 校招笔试 #
471836次浏览 2964人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务