【字符串哈希】Ybt_单词背诵

题目

给你一些单词,再给你一段文章。
要你求此文章中包含多少个给出的单词。
再求文章中的一段,使之包含 给出的单词最多(不计重),输出其最小的长度。


字符串哈希,然后尺取法。
尺取法通常是指对数组保存一对下标(起点,终点),然后根据实际情况交替推进两个端点直到得出答案的方法,这种操作很像是尺取虫爬行的方式故得名。
双重哈希防哈希值重复。


代码

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int ls, flag, ans1, ans2, lans, n, t, l[100010], k1[100010], k2[100010];
bool b[100010];
string s[100010], ss;
struct asdf{
    
    
	int z, next;
} a[100010];
int main(){
    
    
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i){
    
      //读入单词
		cin >> ss;
		ls = ss.size(); 
		int kk1 = 0, kk2 = 0; 
		for(int j = 0; j < ls; ++j)
			kk1 = (kk1 * 13331 + ss[j]) % 10003;
		for(int j = 0; j < ls; ++j)
			kk2 = (kk2 * 10007 + ss[j]) % 10003;
		a[++t] = (asdf){
    
    kk2, l[kk1]}; l[kk1] = t;  //邻接表储存
	}
	scanf("%d", &n);
	ans2 = n;
	for(int i = 1; i <= n; ++i){
    
      //读入文章单词
		cin >> s[i];
		ls = s[i].size(); 
		for(int j = 0; j < ls; ++j)  //计算其哈希值
			k1[i] = (k1[i] * 13331 + s[i][j]) % 10003;
		for(int j = 0; j < ls; ++j)
			k2[i] = (k2[i] * 10007 + s[i][j]) % 10003;
		for(int j = l[k1[i]]; j; j = a[j].next)  //判断是否是要背诵的单词
		  	if(a[j].z == k2[i] && b[j] == 0){
    
    
		    	b[j] = 1;
		  		++ans1; //是。统计入答案
		  		break;
		  	}
	}
	for(int i = 1; i <= n - ans1 + 1; ++i){
    
      //尺取法
		memset(b, 0, sizeof(b));
		lans = 0;
		for(int j = i; j <= n; ++j){
    
    
			for(int k = l[k1[j]]; k; k = a[k].next) 
		    	if(a[k].z == k2[j]){
    
    //如果这个单词是要背的
		  			if(b[k] == 0){
    
      //取的这段中没出现过
		  				b[k] = 1;
		  				++lans;  //计入答案
					}
		  			break;
		  		}
		  	if(lans == ans1) {
    
      //如果背完所需的了
		  		ans2 = min(ans2, j - i + 1); //取最小长度
		  		break;
			}
		}
	}
	printf("%d\n%d", ans1, ans2);  //输出答案
}  

猜你喜欢

转载自blog.csdn.net/qq_42937087/article/details/115015172