• 【CodeVS 2083】Cryptcowgraphy 解密牛语


    http://codevs.cn/problem/2083/

    奶牛搜索题。我加了如下剪枝:

    1.用字符串hash判重。注意判重时也要对字符串长度判重,否则会出现两个字符串长度不同但hash值相同的情况,非常容易被卡hash。

    2.先枚举O,再枚举C,W。枚举W时从后往前枚举。从网上的题解里看到的,具体为什么我也不知道(捂脸)。

    3.对于所有的C,O,W字母可以将字符串切成好几段,但是无论我们怎么交换C-O之间和O-W之间的字符串,这些小段字符串是不会被分开的。所以对于每一个状态我们判断所有C,O,W切成的小段是否在目标串中出现过。这是非常厉害的剪枝。

    4.剪枝3只是判断某些字符串小段是否在目标串中出现过,还可以对这些小段的第一段和最后一段加强限制。即当前串的最小的结尾字符的后一个字符是C的前缀必须是目标串的前缀,当前串最小的开头字符的前一个字符是W的后缀必须是目标串的后缀。这也是非常重要的剪枝。

    有了上面四个剪枝就可以通过此题了。貌似少一个剪枝就会TLE。

    搜索难在分析其玄学的复杂度QAQ

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int w = 140;
    const int p = 1000007;
    const char s[48] = {' ','B','e','g','i','n',' ','t','h','e',' ','E','s','c','a','p','e',' ','e','x','e','c','u','t','i','o','n',' ','a','t',' ','t','h','e',' ','B','r','e','a','k',' ','o','f',' ','D','a','w','n'};
    
    bool showed[9][p + 3];
    int n, Pw[80], hash[50], step;
    
    int gethash(int l, int r) {
    	return (int) ((1ll * hash[r] - 1ll * hash[l - 1] * Pw[r - l + 1] % p + p) % p);
    }
    
    bool flag = false;
    
    bool shown(int ha, int len) {
    	for(int i = len; i <= 47; ++i)
    		if (gethash(i - len + 1, i) == ha) return true;
    	return false;
    }
    
    void dfs(int tmp, char *c, int tot) {
    	if (tmp > step) {
    		for(int i = 1; i <= 47; ++i)
    			if (s[i] != c[i]) return;
    		flag = true; return;
    	}
    	
    	int ret = 0;
    	for(int i = 1; i <= tot; ++i) ret = (int) ((1ll * ret * w + (int) c[i]) % p);
    	if (showed[tmp - 1][ret]) return;
    	showed[tmp - 1][ret] = true;
    	
    	ret = 1;
    	while (c[ret] != 'C' && c[ret] != 'O' && c[ret] != 'W' && ret <= tot) {
    		if (c[ret] != s[ret]) ret = tot + 2;
    		++ret;
    	}
    	if (ret == tot + 2) return;
    	if (ret != tot + 1 && c[ret] != 'C') return;
    	ret = 0;
    	while (c[tot - ret] != 'C' && c[tot - ret] != 'O' && c[tot - ret] != 'W' && ret < tot) {
    		if (c[tot - ret] != s[47 - ret]) ret = tot + 2;
    		++ret;
    	}
    	if (ret == tot + 2) return;
    	if (ret != tot && c[tot - ret] != 'W') return;
    	
    	int head = 1;
    	for(int i = 1; i <= tot; ++i)
    		if (c[i] == 'C' || c[i] == 'O' || c[i] == 'W') {
    			if (head < i) {
    				ret = 0;
    				for(int j = head; j < i; ++j) ret = (int) ((1ll * ret * w + (int) c[j]) % p);
    				if (!shown(ret, i - head)) return;
    			}
    			head = i + 1;
    		}
    	
    	char ch[76];
    	for(int i = 1; i <= tot; ++i)
    		if (c[i] == 'O')
    			for(int j = 1; j < i; ++j)
    				if (c[j] == 'C')
    					for(int k = tot; k > i; --k)
    						if (c[k] == 'W') {							
    							ret = 0;
    							for(int l = 1; l < j; ++l) ch[++ret] = c[l];
    							for(int l = i + 1; l < k; ++l) ch[++ret] = c[l];
    							for(int l = j + 1; l < i; ++l) ch[++ret] = c[l];
    							for(int l = k + 1; l <= tot; ++l) ch[++ret] = c[l];
    							dfs(tmp + 1, ch, ret);
    							if (flag) return;
    						}
    }
    
    char c[80];
    
    int main() {
    	gets(c + 1);
    	n = strlen(c + 1);
    	Pw[0] = 1;
    	for(int i = 1; i <= n; ++i)
    		Pw[i] = (int) (1ll * Pw[i - 1] * w % p);
    	hash[0] = 0;
    	for(int i = 1; i <= 47; ++i)
    		hash[i] = (int) ((1ll * hash[i - 1] * w + (int) s[i]) % p);
    	
    	step = (n - 47) / 3;
    	dfs(1, c, n);
    	
    	if (flag) printf("%d %d
    ", 1, step);
    	else puts("0 0");
    	
    	return 0;
    }
    

    调了一下午+一晚上

  • 相关阅读:
    iOS 性能调优
    Google Nexus 5x Android 7.0 Root
    Android库的标准化(不断更新中)
    Firefox实用插件记录
    关于WordPress搬家方法步骤的整理
    eclipse搭建servlet项目
    Eclipse的FindBugs插件
    常用 Java 静态代码分析工具的分析与比较
    JSONObject简介
    New XAMPP security concept:错误解决方法
  • 原文地址:https://www.cnblogs.com/abclzr/p/5793561.html
Copyright © 2020-2023  润新知