zoukankan      html  css  js  c++  java
  • 前缀哈希

    例题

    原题链接

    ​ 这道题说的就是把一个长度为(n)的串,以(k)个元素为一组进行分段。问当(k)取何值时能分出最多的不同的段。当然在这道题里面,串是可以反转的,就是说如果两个串镜面对称,那么视为他们是一个串。

    ​ 不妨先简化一下,先看当串不能反转时如何进行求解。

    总体思路

    ​ 其实这道题的思路很暴力,因为他用的方法就是暴力。先枚举所有的(k(0leqslant kleqslant n)),再进行去重,最后统计能使长串分成最多不同子串的(k)的值。

    进一步分析

    ​ 我们来看一看这种算法的时间复杂度:枚举(k)需要(O(n))的时间复杂度,在每个(k)之中串有$lfloor frac{n}{k} floor $个。所以算法时间复杂度为

    [sum_{k=1}^n{lfloor frac{n}{k} floor} ]

    将其展开后得到

    [lfloor frac{n}{1} floor +lfloor frac{n}{2} floor +dots +lfloor frac{n}{n} floor ]

    近似于

    [frac{n}{1}+frac{n}{2}+dots +frac{n}{n} ]

    提取(n)

    [nleft( 1+frac{1}{2}+dots +frac{1}{n} ight) ]

    可以看出$left( 1+frac{1}{2}+dots +frac{1}{n} ight) $是调和级数,则

    [1+frac{1}{2}+dots +frac{1}{n}approx ln x<log _2n ]

    得出总时间复杂度为

    [Oleft( nlog n ight) ]

    ​ 现在可以看出,解这道题的时间大部分都花在判断和排重上。所以我们就能想到使用哈希。

    前缀哈希

    ​ 由于这道题的处理对象是串,所以我们能想到利用类似前缀和的思路来构造哈希算法。

    ​ 可以从整数的运算来类比:整数(overline{abcde})可以表示为(a imes 10^4+b imes 10^3+c imes 10^2+d imes 10^1+e imes 10^0)。当我们需要取(overline{bcd})得值时,只需要将(overline{abcde}-e-a imes 10^4)就可以了。

    ​ 那么如果不是(10)进制,而是(P)进制,那么(P)进制数(overline{abcde})可以表示为(a imes P^4+b imes P^3+c imes P^2+d imes P^1+e imes P^0)。(为了优化,在这里定义(p)使(p_i=P^i)

    ​ 这跟哈希有什么关系呢?这就是哈希。把以上的推倒总结成哈希公式就是

    [left{ egin{array}{l} hleft( i ight) =hleft( i-1 ight) +valleft( i ight) cdot p_{i-1}\ hleft( 1 ight) =valleft( 1 ight)\ end{array} ight. ]

    在这之中,(h(i))表示串([0,i])的哈希值。

    ​ 易于发现,这样构造哈希值不一会儿就会超出整数的范围,这时候就可以联想到取模。于是就可以把上面的哈希公式优化成

    [left{ egin{array}{l} hleft( i ight) =left( hleft( i-1 ight) mod m+left( valleft( i ight) cdot p_{i-1} ight) mod m ight) mod m\ hleft( 1 ight) =valleft( 1 ight) mod m\end{array} ight. ]

    这里的(m)需要大质数,以减少哈希碰撞。

    ​ 会了构造,还要能提取。不难看出,提取公式是

    [hleft( i,j ight) =hleft( j ight) -hleft( i-1 ight) cdot p_{j-i+1} ]

    (h(i,j))表示串([i,j])的哈希值。(可以类比十进制)

    代码实现

    ​ 现在来用代码对照上面的思路,辅助理解,我尽量让代码中的变量和代码对应。(不要试图用这段代码去通过原题,它没有考虑逆序的情况)

    #include <iostream>
    #include <vector>
    #include <map>
    using namespace std;
    
    const unsigned int P = 19260817; // 进制位
    const unsigned int m = 19260817; // 模数
    
    int main() {
    
    	int n = 0;
    	int val[200001] = { 0 };
    	unsigned long long int p[200001] = { 1 };
    	unsigned long long int h[200001] = { 1 };
    	map<unsigned long long int, bool> mp;
    	int maxn = 0;
    	vector<int> result;
    	// 读入
    	cin >> n;
    	for (int iter = 1; iter <= n; iter++) {
    		cin >> val[iter];
    	}
    	// 预处理哈希
    	for (int iter = 1; iter <= n; iter++) {
    		h[iter] = h[iter - 1] + val[iter] * p[iter - 1];
    	}
    	// 枚举k
    	for (int k = 1; k <= n; k++) {
    		int count = 0;
    		mp.clear();
    		// 分段
    		for (int i = 1; i <= n / k; i++) {
    			int j = i + k; // i和j表示串[i,j]
    			int H = (h[j]%m - (h[i - 1] * p[j - i + 1])%m)%m; // 计算哈希
    			// 利用map判重
    			if (!mp[H]) {
    				mp[H] = true;
    				count++;
    			}
    		}
    		// 更新答案
    		if (maxn == count) {
    			result.push_back(count);
    		}
    		if (maxn < count) {
    			result.clear();
    			result.push_back(count);
    		}
    	}
    	// 打印答案
    	cout << result[0] << result.size() << endl;
    	for (int iter = 0; iter < result.size(); iter++) {
    		cout << result[iter] << " ";
    	}
    	return 0;
    }
    
  • 相关阅读:
    Building a Space Station POJ
    Networking POJ
    POJ 1251 Jungle Roads
    CodeForces
    CodeForces
    kuangbin专题 专题一 简单搜索 POJ 1426 Find The Multiple
    The Preliminary Contest for ICPC Asia Shenyang 2019 F. Honk's pool
    The Preliminary Contest for ICPC Asia Shenyang 2019 H. Texas hold'em Poker
    The Preliminary Contest for ICPC Asia Xuzhou 2019 E. XKC's basketball team
    robotparser (File Formats) – Python 中文开发手册
  • 原文地址:https://www.cnblogs.com/Iuppiter/p/12903932.html
Copyright © 2011-2022 走看看