【第0002页 · 枚举】月月查华华的手机

【前言】本文以及之后的一些题解都会陆续整理到目录中,若想了解全部题解整理,请看这里:

第0002页 · 月月查华华的手机

        不知道在看的各位有没有被家里人查过手机呢?如果有,想必今天你会感同身受一些。我们现在要来看一道比较有意思的题目,其中涉及到的字符查找的思想很有意义。话不多说,先看题目。

【月月查华华的手机】月月和华华一起去吃饭了。期间华华有事出去了一会儿,没有带手机。月月出于人类最单纯的好奇心,打开了华华的手机。哇,她看到了一片的QQ推荐好友,似乎华华还没有浏览过。月月顿时醋意大发,出于对好朋友的关心,为了避免华华浪费太多时间和其他网友聊天,她要删掉一些推荐好友。但是为了不让华华发现,产生猜疑,破坏了他们的友情,月月决定只删华华有可能搭讪的推荐好友。
        月月熟知华华搭讪的规则。华华想与某个小姐姐搭讪,当且仅当小姐姐的昵称是他的昵称的子序列。为了方便,华华和小姐姐的昵称只由小写字母构成。为了更加方便,保证小姐姐的昵称长度不会比华华的长。
        现在月月要快速的判断出哪些推荐好友要删掉,因为华华快回来了,时间紧迫,月月有点手忙脚乱,所以你赶紧写个程序帮帮她吧!

        其中要求:1 <= A <= 1e6 ;  1 <= N <= 1e6 ; 1 <= sum[Bi] <= 1e6。

IO要求示例
输入描述:
第一行输入一个字符串A表示华华的昵称。
第二行输入一个正整数N表示华华的推荐好友的个数。
接下来N行,每行输入一个字符串Bi,Bi​表示某个推荐好友的昵称。

noiauwfaurainairtqltqlmomomo
8
rain
air
tql
ntt
xiaobai
oiiiooo
orzcnzcnznb
ooooo

输出描述:
输出N行,对于第i个推荐好友,如果华华可能向她搭讪,输出Yes,否则输出No。
注意大写,同时也要注意输出效率对算法效率的影响。

Yes

Yes

Yes

Yes

No

Yes

No

No

【解题分析】这道题目中需要我们对所有小姐姐的字符串在华华中查找一遍,判断是否是其子串。这里我们首先强调一个概念,在题目中没有说连续子字符串时,所谓的子串是可以不连续的,但是顺序要保持一致。

        我们最开始的思路肯定是对每个小姐姐字符串都将华华字符串扫一遍,但此时根据所给数据范围,最坏情况下为 10^12。这是不可以的,因此,我们考虑如何快速地检索字符是本题的关键。

        这里,我们给出的思路是:构造一个二维数组用来存储华华的每一位字符之后的下一个字符‘a’,'b','c',...... 分别在什么位置,这样就可以直接跳过中间的其余字符,大大减少检索遍历的次数,从而使最坏情况变为 10^6。这样就符合题目要求了。

        有了思路,我们就来写代码了,一些细节部分会在代码中以注释的形式给出,请注意查收哦!

【源码展示】

#include <cstdio>
#include <cstring>
using namespace std;
const int num = 1e6 + 10;
// nex[][]用来存储每一位字符的下一个字符所在位置
// case[]用来不断刷新下一字符所在位置
int nex[num][30], cast[30]; 
int main() {
    char name[num];
    scanf("%s", name);
    int len = strlen(name);
    // 如果下一个字符,例如'a'不存在了,则它的下一个位置记为-1,表示不存在
    memset(cast, -1, sizeof(cast));
    // 将每个字符之后的下一个字符的位置存储下来
    // 从尾部开始遍历,这样就能确保每次刷新一个字符所在的位置即可
    // 但之前需要先把这个位置之后的字符位置存入nex[][]中再刷新cast[]
    for (int i = len - 1; i >= 0; i--) {
        for (int j = 0; j < 26; j++) {
            nex[i][j] = cast[j];
        }
        cast[name[i] - 'a'] = i;
    }
    int N;
    scanf("%d", &N);
    while (N--) {
        int flag = 1; // 1表示Yes
        char girl[num];
        scanf("%s", girl);
        int len1 = strlen(girl);
        // pos用来记录按照小姐姐字符串的下一位字符在华华字符串中的位置
        // 如果出现pos == -1,那么就证明这个小姐姐不是华华的子串
        int pos = cast[girl[0] - 'a'];
        if (pos == -1) {
            printf("No\n");
            continue;
        }
        for (int i = 1; i < len1; i++) {
            pos = nex[pos][girl[i] - 'a'];
            if (pos == -1) {
                flag = 0;
                break;
            }
        }
        if (flag == 1) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个比较简单的数学题,可以用矩阵快速幂求解。以下是 C++ 代码实现: ```c++ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int MAXN = 2; const int MOD = 1e9 + 7; struct Matrix { LL m[MAXN][MAXN]; Matrix() { memset(m, 0, sizeof(m)); } Matrix operator * (const Matrix& b) const { Matrix c; for (int i = 0; i < MAXN; ++i) { for (int j = 0; j < MAXN; ++j) { for (int k = 0; k < MAXN; ++k) { c.m[i][j] = (c.m[i][j] + m[i][k] * b.m[k][j]) % MOD; } } } return c; } } base, res; Matrix qpow(Matrix a, int b) { Matrix ans; for (int i = 0; i < MAXN; ++i) { ans.m[i][i] = 1; } while (b) { if (b & 1) { ans = ans * a; } a = a * a; b >>= 1; } return ans; } LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); } int main() { LL a, b, n; cin >> a >> b >> n; if (n == 1) { cout << a << endl; } else if (n == 2) { cout << b << endl; } else { base.m[0][0] = base.m[0][1] = base.m[1][0] = 1; res = qpow(base, n - 2); LL ans = gcd(a * res.m[0][0] % MOD + b * res.m[1][0] % MOD, b * res.m[1][0] % MOD + b * res.m[1][1] % MOD); cout << ans << endl; } return 0; } ``` 在这段代码中,我们定义了一个 `Matrix` 结构体,它表示一个 $2\times2$ 的矩阵。其中重载了 `*` 运算符,实现了矩阵乘法。 然后,我们定义了一个矩阵快速幂函数 `qpow`,用于求解矩阵的 $n$ 次方。 最后,在 `main` 函数中,我们通过快速幂求出矩阵 $base$ 的 $n-2$ 次方,然后根据题目要求求出 $\gcd(F_N, F_{N+1})$ 并输出即可。 需要注意的是,当 $n=1$ 或 $n=2$ 时,直接输出 $a$ 或 $b$ 即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值