• [ural 2118]. Ciphertext


    题意

    ……(语文水平差)

    题解

    首先如果加密串中同时有串01,那么答案为-1;如果加密串中同时没有串01,那么答案为(|S'|)
    否则我们假设加密串中只有0没有1
    注意到题目给出加密串没有一个是另一个前缀,则一段形如00...01这样的东西就是合法的。
    我们如果找到了一个后缀,满足它不能被解密,那么从它前面的第一个1后切开,答案就是前面的1的总数+1。
    (即分段的形式为00...01|00...01|...|00...01|UndecodableSuffix
    显然我们要对于所有不能被解密的后缀求一个最短的。
    这个东西只要把反串建AC自动机即可。
    复杂度(mathcal O(|S|k))

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e4 + 5, M = 55;
    int n, k, siz;
    string oS, S[M];
    int c[N * M][2], ed[N * M], fail[N * M];
    queue <int> q;
    void append (string s) {
    	int len = s.size(), u = 0;
    	for (int i = len - 1, x; ~i; --i) {
    		x = s[i] - '0';
    		if (!c[u][x]) {
    			c[u][x] = ++siz;
    		}
    		u = c[u][x];
    	}
    	ed[u] = 1;
    }
    void build () {
    	for (int i = 0; i < 2; ++i) {
    		if (c[0][i]) {
    			fail[c[0][i]] = 0;
    			q.push(c[0][i]);
    		}
    	}
    	for ( ; !q.empty(); q.pop()) {
    		int u = q.front();
    		for (int i = 0; i < 2; ++i) {
    			if (c[u][i]) {
    				fail[c[u][i]] = c[fail[u]][i];
    				ed[c[u][i]] |= ed[c[fail[u]][i]];
    				q.push(c[u][i]);
    			} else {
    				c[u][i] = c[fail[u]][i];
    			}
    		}
    	}
    }
    int id (char c) {
    	return isupper(c) ? c - 'A' + 1 : c - 'a' + 27;
    }
    int solve () {
    	int ret = -1, fl = 0, p = 0, m = oS.size();
    	for (int i = m - 1, x; i >= 0; --i) {
    		x = id(oS[i]);
    		for (int j = S[x].size() - 1; ~j; --j) {
    			p = c[p][S[x][j] - '0'];
    			ret += (S[x][j] - '0') * fl;
    			if (!fl && !ed[p]) {
    				fl = 1, ret = 1;
    			}
    		}
    	}
    	return ret;
    }
    int main () {
    	cin >> n >> oS, k = 0;
    	for (int i = 1; i <= n; ++i) {
    		cin >> S[i];
    		if (S[i].size() == 1 && S[i] == "0") {
    			k |= 1;
    		}
    		if (S[i].size() == 1 && S[i] == "1") {
    			k |= 2;
    		}
    	}
    	if (k == 0) {
    		int ans = 0;
    		for (int i = 0; i < (int)oS.size(); ++i) {
    			ans += S[id(oS[i])].size();
    		}
    		cout << ans << endl;
    		return 0;
    	}
    	if (k == 3) {
    		return cout << -1 << endl, 0;
    	}
    	if (k == 2) {
    		for (int i = 1, len; i <= n; ++i) {
    			len = S[i].size();
    			for (int j = 0; j < len; ++j) {
    				S[i][j] = '0' + '1' - S[i][j];
    			}
    		}
    	}
    	for (int i = 1; i <= n; ++i) {
    		append(S[i]);
    	}
    	build();
    	cout << solve() << endl;
    	return 0;
    }
    
  • 相关阅读:
    centos出现“FirewallD is not running”怎么办
    百度编辑器(Ueditor)最新版(1.4.3.3)插入锚点失败原因分析及BUG修复
    centos rm -rf 恢复删除的文件
    php实现粘贴截图并完成上传功能
    微信网页授权java实现
    JAVA使用POI读取EXCEL文件的简单model
    java读取excel文件数据
    java文件操作(读流)
    oracle 10g正则表达式 REGEXP_LIKE 用法
    Oracle正则表达式函数:regexp_like、regexp_substr、regexp_instr、regexp_replace
  • 原文地址:https://www.cnblogs.com/psimonw/p/11808270.html
Copyright © 2020-2023  润新知