NOIP2001 统计单词个数 rabin-karp哈希

本文介绍了一种使用Rabin-Karp哈希算法优化NOIP2001统计单词个数问题的解决方案,通过动态规划实现字符串匹配,确保在限定条件下找到最大的单词组合数量。

1233: NOIP2001:统计单词个数

时间限制: 0 Sec  内存限制: 128 MB
提交: 8  解决: 6
[上一题][提交][讨论版][状态][下一题]

题目描述

        给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1< k< =40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。

        单词在给出的一个不超过6个单词的字典中。

        要求输出最大的个数。

输入

第一行有二个正整数(p,k)

p表示字串的行数;k表示分为k个部分。

接下来的p行,每行均有20个字符。

再接下来有一个正整数s,表示字典中单词个数。(1< =s< =6)

接下来的s行,每行均有一个单词。

输出

输出一个整数,即最大的个数

样例输入

1 3
thisisabookyouareaoh
4
is
a
ok
sab

样例输出

7

提示

NOIP2001提高组第三题

我用的是主流dp,所以这里不讲dp, 讲如何处理字符串。

我用的是rabin-karp哈希

记前 i 位的哈希值 为 hx[i]

搞一个base, 我的是131

hx[i] = (hx[i-1] * base + s[i]) % mod P

P是个大素数, 我选的是1e9+7

这样我们的hx[i]就等于 s[1]*base^i-1 + s[2]*base^i-2 + ..... s[i]*base^0

我们要求l, r的哈希值, 观察一下hx[l-1] 和 hx[r]

hx[l-1] = s[1]*base^l-2 + s[2]*base^l-3 + .....s[l-1]*base^0

hx[r] = s[1]*base^r-1 + s[2]*base^r-2 + .....s[r]*base^0

我们只看s[1]的指数就行了(后面一样的)

于是我们将hx[l-1]乘上 base^r-l+1次方, 用hx[r]一减, 从s[1]到s[l-1]的值全被消掉了

我们就得到了 [l, r]的哈希值

然后就dp就行了

dp也有一个坑的地方, 因为一定要分成k份, 不能 < k份, 所以我们在 f[t][j-1] 有值的时候才转移

代码如下:

#include <cstdio>
#include <string.h>
#define ll long long
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define base 131
#define mod 1000000007
ll hx[205], re[205], po[205], t, hav[205][205], s, l[7];
int f[205][205];
char a[205], b[25], c[1005];
int len;
ll gethash(int l, int r){
    return ((hx[r] - po[r-l+1]*hx[l-1])%mod+mod) % mod;
}
int get(int x, int y){
    int i;
    for(i = 1; i <= s; i++) if(gethash(x, min(y, x+l[i]-1)) == re[i]) return 1;
    return 0;
}
int main(){
    int i, j, p, k, n;
    scanf("%d%d", &p, &k);
    scanf("%s", a+1);
    len = strlen(a+1);
    for(i = 2; i <= p; i++){
        scanf("%s", b+1);
        n = strlen(b+1);
        for(j = len+1; j <= len+n; j++) a[j] = b[j-len];
        len += n;
    }
    for(i = po[0] = 1; i <= len; i++){
        po[i] = po[i-1] * base % mod;
        hx[i] = (hx[i-1] * base + a[i]) % mod;
    }
    scanf("%d", &s);
    for(i = 1; i <= s; i++){
        scanf("%s", c+1);
        n = strlen(c+1);
        l[i] = n;
        t = 0;
        for(j = 1; j <= n; j++) t = (t * base + c[j]) % mod;
        re[i] = t;
    }
    for(i = len; i >= 1; i--){
        for(j = i; j >= 1; j--){
            hav[j][i] = hav[j+1][i];
            hav[j][i] += get(j, i);
        }
    }
    for(i = 1; i <= len; i++){
        f[i][1] = hav[1][i];
        for(j = 2; j <= k; j++){
            for(t = 1; t < i; t++){
                if(f[t][j-1]) f[i][j] = max(f[i][j], f[t][j-1] + hav[t+1][i]);
            }
        }
    }
    printf("%d", f[len][k]);
    return 0;
}


本指南详细阐述基于Python编程语言结合OpenCV计算机视觉库构建实时眼部状态分析系统的技术流程。该系统能够准确识别眼部区域,并对眨眼动作与持续闭眼状态进行判别。OpenCV作为功能强大的图像处理工具库,配合Python简洁的语法特性与丰富的第三方模块支持,为开发此类视觉应用提供了理想环境。 在环境配置阶段,除基础Python运行环境外,还需安装OpenCV核心模块与dlib机器学习库。dlib库内置的HOG(方向梯度直方图)特征检测算法在面部特征定位方面表现卓越。 技术实现包含以下关键环节: - 面部区域检测:采用预训练的Haar级联分类器或HOG特征检测器完成初始人脸定位,为后续眼部分析建立基础坐标系 - 眼部精确定位:基于已识别的人脸区域,运用dlib提供的面部特征点预测模型准确标定双眼位置坐标 - 眼睑轮廓分析:通过OpenCV的轮廓提取算法精确勾勒眼睑边缘形态,为状态判别提供几何特征依据 - 眨眼动作识别:通过连续帧序列分析眼睑开合度变化,建立动态阈值模型判断瞬时闭合动作 - 持续闭眼检测:设定更严格的状态持续时间与闭合程度双重标准,准确识别长时间闭眼行为 - 实时处理架构:构建视频流处理管线,通过帧捕获、特征分析、状态判断的循环流程实现实时监控 完整的技术文档应包含模块化代码实现、依赖库安装指引、参数调优指南及常见问题解决方案。示例代码需具备完整的错误处理机制与性能优化建议,涵盖图像预处理、光照补偿等实际应用中的关键技术点。 掌握该技术体系不仅有助于深入理解计算机视觉原理,更为疲劳驾驶预警、医疗监护等实际应用场景提供了可靠的技术基础。后续优化方向可包括多模态特征融合、深度学习模型集成等进阶研究领域。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
### Python 实现统计单词个数 要实现统计单词个数的功能,可以通过读取文本文件并逐行处理内容来完成。以下是基于引用的内容以及扩展的知识所提供的解决方案。 #### 解决方案描述 为了满足题目需求,程序需具备以下功能: 1. **读取输入数据**:从标准输入或指定文件中获取待分析的文本。 2. **预处理文本**:将文本转换为统一的小写形式,并去除多余的空白符以便于后续操作[^1]。 3. **分割单词**:通过空格或其他分隔符分离出单个单词。 4. **统计单词频率**:利用 `collections.Counter` 或字典结构记录每个单词出现的次数。 5. **输出结果**:按照要求格式化输出单词及其对应频次。 下面是一个完整的 Python 代码示例: ```python import re from collections import Counter def count_words(text, target_word=None): # 将所有字母转为小写以忽略大小写的差异 text = text.lower() # 使用正则表达式提取单词,过滤掉非字母字符 words = re.findall(r'\b\w+\b', text) # 如果目标单词为空,则计算整个文档的词频分布 word_counts = Counter(words) if target_word is None: result = dict(word_counts.most_common()) else: # 转为目标单词的小写版本用于比较 target_word = target_word.lower() result = {target_word: word_counts[target_word]} return result if __name__ == "__main__": input_text = """ This is a sample text with several words. The task involves counting the occurrences of each distinct word, ignoring case and punctuation marks such as commas or periods. """ # 假设用户希望查询某个特定单词 specific_word = "word" output = count_words(input_text, specific_word) print(f"Word '{specific_word}' appears {output[specific_word]} times.") # 查询整体词频分布 all_word_frequencies = count_words(input_text) print("Overall Word Frequencies:") for word, freq in all_word_frequencies.items(): print(f"{word}: {freq}") ``` 上述代码实现了两个主要功能:一是单独统计某一个单词在文本中的出现次数;二是返回整个文本中各单词的频率表[^2]。 #### 关键技术点解析 - **字符串标准化**:通过 `.lower()` 方法使大写字母变为小写,从而简化匹配逻辑。 - **正则表达式应用**:借助 `re.findall('\b\w+\b')` 提取出合法的英语单词序列[^3]。 - **高效计数工具**:采用 `Counter` 类型自动汇总重复项的数量,减少手动维护哈希表的工作量[^4]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值