洛谷P2922 [USACO08DEC]Secret Message G 题解

本文详细介绍了洛谷P2922题目的解题思路和代码实现。题目涉及奶牛之间的秘密信息传递,约翰试图通过已知的部分信息匹配奶牛的暗号。解题方法是利用Trie树来处理二进制前缀匹配问题,实现了O(∑bi+M∑ci)的时间复杂度。代码中展示了如何插入信息和进行查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

洛谷P2922 [USACO08DEC]Secret Message G 题解

题目链接:P2922 [USACO08DEC]Secret Message G

题意

一句话题意: m m m 次询问,查询已有的 n n n 01 \tt{01} 01 串中,有多少串 t i t_i ti 能使询问串 s s s 成为其前缀。

贝茜正在领导奶牛们逃跑.为了联络,奶牛们互相发送秘密信息.

信息是二进制的,共有 M M M 1 ≤ M ≤ 50000 1 \le M \le 50000 1M50000)条,反间谍能力很强的约翰已经部分拦截了这些信息,知道了第 i i i 条二进制信息的前 b i b_i bi l ≤ b i ≤ 10000 l \le b_i \le 10000 lbi10000)位,他同时知道,奶牛使用 N N N 1 ≤ N ≤ 50000 1 \le N \le 50000 1N50000)条暗号.但是,他仅仅知道第 j j j 条暗号的前 c j c_j cj 1 ≤ c j ≤ 10000 1 \le c_j \le 10000 1cj10000)位。

对于每条暗号 j j j,他想知道有多少截得的信息能够和它匹配。也就是说,有多少信息和这条暗号有着相同的前缀。当然,这个前缀长度必须等于暗号和那条信息长度的较小者。

在输入文件中,位的总数(即 ∑ b i + ∑ c i \sum b_i + \sum c_i bi+ci)不会超过 500000 500000 500000

考虑建 t r i e \tt{trie} trie 树处理

没了,就这么简单。

具体见代码,有一些小的细节要注意

时间复杂度 O ( ∑ b i + M ∑ c i ) O(\sum b_i + M \sum c_i) O(bi+Mci)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(5e5+15)

string str;
int n,m,k,tot;
struct Trie
{
    int trie[N][2],ed[N],sum[N];
    void insert(int l)
    {
        int u=0;
        for(int i=1,c; i<=l; i++)
        {
            cin >> c;
            if(!trie[u][c])trie[u][c]=++tot;
            ++sum[u=trie[u][c]];
        }
        ++ed[u];
    }
    int query(int l)
    {
        int u=0,ok=1,res=0;
        for(int i=1,c; i<=l; i++)
        {
            cin >> c;
            if(!trie[u][c])
            {
                while(++i<=l) cin >> c;
                return res;
            };
            res+=ed[u=trie[u][c]];
        }
        return res-ed[u]+sum[u]; // ed[u]是sum[u]的子集
    }
}tr;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m;
    for(int i=1,x; i<=n; i++)
    {
        cin >> x;
        tr.insert(x);
    }
    for(int i=1,x; i<=m; i++)
    {
        cin >> x;
        cout << tr.query(x) << '\n';
    }
    return 0;
}

转载请说明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值