• 「UVA 1673」「LA 6387」「HDU 4436」str2int


    Description

    在这个问题中,您将得到几个字符串,这些字符串只包含 “0” 到 “9” 的数字。

    字符串的集合 (S) 由输入给定的 (n) 个字符串和每个字符串的所有可能的字串组成。

    操作字符串很无聊,所以你决定把 (S) 中的字符串转化整数。

    可以将只包含数字的字符串转化为十进制整数,例如,可以将 “101” 转化为 101,将 “01” 转化为 1,等等。

    如果一个整数出现多次,则保留其中一个。你的任务是计算所有整数的和除以 2012 的余数。

    多组数据,读到 EOF 结束。

    Hint

    • (1le nle 10^4)
    • (1le sum ext{字符串长度}le 10^5)

    Solution

    在解决这个问题前,我们不妨考虑一下对单个串要怎么做。

    子串的问题,SAM 是一个强有力的工具。首先对整个串建 SAM,然后对建出来的这个 DAG 求拓扑序,然后大力 dp。

    设:(f(x), s(x)) 分别表示从初始状态到 (x)不含前导 0 的合法 的不同子串的数量,以及 所有合法路径对应的子串的数字的总和

    那么状态转移方程:

    [f(y) = sumlimits_{y in ext{sons of }x} f(x) \ s(y) = sumlimits_{{delta (x, c)=y}in ext{SAM}} s(x) + f(x) imes c ]

    为了避免把前导 0 计算进去,可以约定,初始状态不能走 0 边。


    现在考虑如何做多串。其实也很简单:只要将所有串拼接在一起即可。在串与串之间插入一些无用字符(如 ( exttt{#}))。

    然后对拼接串建 SAM。在走的时候,除了上面的前导 0 的处理,还要规定避开无用字符的转移边。

    复杂度(map 版):(O(sum| ext{str_len}| imes log|Sigma|))

    Code

    /*
     * Author : _Wallace_
     * Source : https://www.cnblogs.com/-Wallace-/
     * Problem : UVA 1673 LA 6387 HDU 4436 str2int
     */
    #include <iostream>
    #include <map>
    #include <string>
    
    using namespace std;
    const int N = 2e5 + 5;
    const int mod = 2012;
    
    namespace SAM {
    	const int T = N << 1;
    	struct Node {
    		map<char, int> ch;
    		int link, len;
    	} t[T];
    	
    	int total;
    	int last;
    	
    	void extend(char c) {
    		int p = last, np = last = ++total;
    		t[np].len = t[p].len + 1;
    		
    		for (; p && !t[p].ch.count(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[q].len == t[p].len + 1) {
    				t[np].link = q;
    			} else {
    				int nq = ++total;
    				t[nq].ch = t[q].ch, t[nq].link = t[q].link;
    				t[nq].len = t[p].len + 1;
    				t[q].link = t[np].link = nq;
    				while (p && t[p].ch.count(c) && t[p].ch[c] == q)
    					t[p].ch[c] = nq, p = t[p].link;
    			}
    		}
    	}
    	void init(string& s) {
    		for (register int i = 1; i <= total; i++) t[i] = Node();
    		last = total = 1;
    		for (string::iterator it = s.begin(); it != s.end(); it++) extend(*it);
    	}
    	
    	int b[T], c[T];
    	void topo_sort() {
    		for (register int i = 1; i <= total; i++) b[i] = c[i] = 0;
    		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;
    	}
    	
    	int f[T], s[T];
    	int calc();
    };
    
    int SAM::calc() {
    	for (register int i = 1; i <= total; i++) f[i] = s[i] = 0;
    	
    	f[1] = 1;
    	for (register int i = 1; i <= total; i++) {
    		int x = b[i];
    		for (map<char, int>::iterator it = t[x].ch.begin(); it != t[x].ch.end(); it++) {
    			int y = it->second, c = it->first;
    			
    			if (char(c) == '0' && x == 1) continue;
    			if (char(c) == '#') continue;
    			
    			(f[y] += f[x]) %= mod;
    			(s[y] += s[x] * 10 + f[x] * (c - '0')) %= mod;
    		}
    	}
    	
    	int ans = 0;
    	for (register int i = 1; i <= total; i++)
    		(ans += s[i]) %= mod;
    	return ans;
    }
    
    signed main() {
    	ios::sync_with_stdio(false);
    	
    	int n;
    	while (cin >> n) {
    		string str = "", tmp;
    		
    		while (n--) {
    			cin >> tmp;
    			str.append("#");
    			str.append(tmp);
    		}
    		str.erase(str.begin());
    		
    		SAM::init(str);
    		SAM::topo_sort();
    		
    		cout << SAM::calc() << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    个人博客设计:创建Sql数据库操作类。
    文件 md5 查看 命令
    https 理解
    ie8、9 post 跨域
    tomcat https
    wamp 初始化 修改mysql密码
    面试-Android之java基础
    apktool.bat
    面试------Android 版本之前的差异(常见,欢迎补充)。
    ubuntu kylin 设置 wifi
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/12938063.html
Copyright © 2020-2023  润新知