zoukankan      html  css  js  c++  java
  • 「Codeforces 235C」Cyclical Quest

    Description

    给定一个字符串 (S),以及 (m) 个询问。

    每个询问给出一个字符串 (T),求 (T) 的所有循环同构在 (S) 中出现的次数总和。

    Hint

    • (1le nle 10^5)
    • (1le |S| le 10^6)
    • (1le sum|T| le 10^6)

    Solution

    后缀自动机

    一个比较简单的思路是,先对 (S) 建 SAM,顺便处理出 ( ext{end-pos}) 集大小。

    然后对于每一个 (T),将其拆成 (|T|) 个字符串分别放在 SAM 上跑,把所有结果求和即可。

    但这样一次复杂度为 (O(|T|^2)),这样的算法显然不可行。


    我们将 (T) 复制一遍接在后面,记为 (R)

    注意到 (R) 中包含了所有 (T) 的循环同构的字符串,所以可以用 (R) 直接在 SAM 上跑

    如果当前匹配出的长度大于 (|T|),那么 强制失配。因为显然怎么循环都不会有这么长的串,而这个现象是复制所导致的。

    为避免应旋转产生相同字符串对答案的影响,可以用一个标记数组。

    时间,空间复杂度:(O(|S| + sum|T|))(O(|S|))。(字符集大小记为常数)

    Code

    /*
     * Author : _Wallace_
     * Source : https://www.cnblogs.com/-Wallace-/
     * Problem : Codeforces 235C Cyclical Quest
     */
    #include <iostream>
    #include <map>
    #include <string>
    
    using namespace std;
    const int N = 1e5 + 5;
    const int L = 1e6 + 5;
    
    namespace SAM {
    	const int T = L << 1;
    	struct Node {
    		map<char, int> ch;
    		int link, len, size;
    	} t[T];
    	
    	int last;
    	int total;
    	
    	void extend_char(char c) {
    		int p = last, np = last = ++total;
    		t[np].len = t[p].len + 1;
    		
    		for (; p && !t[p].ch[c]; p = t[p].link)
    			t[p].ch[c] = np;
    		
    		if (!p) {
    			t[np].link = 1;
    		} else {
    			int q = t[p].ch[c];
    			if (t[p].len + 1 == t[q].len) {
    				t[np].link = q;	
    			} else {
    				int nq = ++total;
    				t[nq] = t[q], t[nq].len = t[p].len + 1, t[nq].size = 0;
    				t[np].link = t[q].link = nq;
    				for (; p && t[p].ch[c] == q; p = t[p].link)
    					t[p].ch[c] = nq;
    			}
    		}
    		t[np].size = 1;
    	}
    	
    	int b[T], c[T];
    	void init_data(string& s) {
    		last = total = 1;
    		for (string::iterator it = s.begin(); it != s.end(); it++)
    			extend_char(*it);
    		
    		for (register int i = 1; i <= total; i++) ++c[t[i].len];
    		for (register int i = 1; i <= total; i++) c[i] += c[i - 1];
    		for (register int i = 1; i <= total; i++) b[c[t[i].len]--] = i;
    		
    		for (register int i = total; i; i--) {
    			int x = b[i], f = t[x].link;
    			t[f].size += t[x].size;
    		}
    	}
    	
    	int vis[T];
    	long long count(string& str, int time);
    };
    
    long long SAM::count(string& str, int time) {
    	long long ret = 0ll;
    	int x = 1, len = 0;
    	
    	str = str + str;
    	for (register int i = 0; i < str.size(); i++) {
    		char c = str[i];
    		while (x && !t[x].ch[c]) x = t[x].link, len = t[x].len;
    		if (!x) x = 1, len = 0;
    		else x = t[x].ch[c], len++;
    		
    		while (x && t[t[x].link].len >= str.size() / 2)
    			x = t[x].link, len = t[x].len;
    		if (len >= str.size() / 2 && vis[x] != time)
    			ret += t[x].size, vis[x] = time;
    	}
    	return ret;
    }
    
    signed main() {
    	ios::sync_with_stdio(false);
    	
    	string str;
    	cin >> str;
    	SAM::init_data(str);
    	
    	int m;
    	cin >> m;
    	for (register int time = 1; time <= m; time++) {
    		cin >> str;
    		cout << SAM::count(str, time) << endl;
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    AngularJS各种'service'的区别
    js 斐波那契数列实现
    Mac下Apache+MySQL+PHP开发环境安装过程
    原生封装的js前端工具库(包含了jquery的常用功能)
    BFC 神奇背后的原理
    CSS清浮动处理(Clear与BFC)
    JavaScript实现 页面滚动图片加载(懒加载)
    CodeForce 814B
    排序算法
    uva1610
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/13056348.html
Copyright © 2011-2022 走看看