码迷,mamicode.com
首页 > 其他好文 > 详细

「UVA 1673」「LA 6387」str2int

时间:2020-05-22 17:00:51      阅读:50      评论:0      收藏:0      [点我收藏+]

标签:lan   using   转化   strong   工具   ios   ons   包含   lin   

Description

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

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

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

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

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

多组数据,读到 EOF 结束。

Hint

  • \(1\le n\le 10^4\)
  • \(1\le \sum \text{字符串长度}\le 10^5\)

Solution

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

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

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

那么状态转移方程:

\[f(y) = \sum\limits_{y \in \text{sons of }x} f(x) \s(y) = \sum\limits_{\{\delta (x, c)=y\}\in \text{SAM}} s(x) + f(x)\times c \]

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


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

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

复杂度(map 版):\(O(\sum|\text{str_len}|\times \log|\Sigma|)\)

Code

#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;
}

「UVA 1673」「LA 6387」str2int

标签:lan   using   转化   strong   工具   ios   ons   包含   lin   

原文地址:https://www.cnblogs.com/-Wallace-/p/12938063.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!