这道题目需要大量优化,要用到ELFhash字符串哈希,空间不能开太大,否则会很慢,但是在我的机器上试,空间不影响速度,有可能是因为usaco服务器的问题
总结一下错误的地方
1)下标错误:把c,o,w搞混了
2)边界错误:对于字符数组,需要判断0<=i && i < n,一般在有+-的时候容易出错,更一般的,加法和乘法注意溢出,减法注意负数,除法注意除数为0的情况
优化措施总结如下
1)字符串的字符个数应该等于(目标字符串的长度)+3*k。如果不满足就可直接判断无解。
2)除了COW三个字符外,其他的字符的个数应该和目标串相一致。如果不一致也可直接判断无解。前两项都可以在搜索前进行 .
3)搜索中间肯定会出现很多字符串相同的情况,因此需要开一个hash来判断是否搜索过,用ELFhash可以对字符串很好的处理 ,这里哈希数组大小为131071
4)一个有解的字符串中,COW三个字母最早出现的应该是C,最后出现的应该是W,如果不满足则剪枝。
5)当前字符串被COW分为几个子串,每个子串一定也是目标串的子串,如果不符合可立即剪枝, 也可以用hash来存储。
6)需要优化搜索顺序。先枚举O,并且W要逆序枚举
经过上述优化,程序对于极端数据也可以在1s以内出解。
以下是我的代码
- #include <iostream>
- #include <algorithm>
- #include <string>
- #include <map>
- using namespace std;
- /*
- PROG: cryptcow
- LANG: C++
- ID: heben991
- */
- const int N = 80, M = 256, D = 80, hash_size = 131071;
- // too large hash_size will be slow!!
- char code[N] = "Begin the Escape execution at the Break of Dawn";
- int len = strlen(code);
- int code_cnt[M], str_cnt[M];
- char s[D][N], ss[N], *p, ch, cow[5]="COW";
- bool hash[hash_size], code_hash[hash_size];
- int ELFhash(char *key)
- {
- unsigned long h=0,g;
- while(*key)
- {
- h=(h<<4) + *key++;
- g=h & 0xF0000000L;
- if(g) h^= g>>24;
- h &= ~g;
- }
- return h % hash_size;
- }
- bool impossible(char *s, int n)
- {
- int i=0, j, c, w;
- for(c = 0; c < n && s[c]!='C'; ++c);
- for(w = n-1; w >=0 && s[w]!='W'; --w);
- if(c < n && w >= 0 && c >= w)return true;
- strcpy(ss,s);
- p = strtok(ss,cow);
- while(p)
- {
- if(!code_hash[ELFhash(p)])return true;
- p = strtok(0,cow);
- }
- return false;
- }
- bool ok(int deep, int n)
- {
- int i, t, c, o, w;
- if(strcmp(s[deep],code)==0)
- {
- return true;
- }
- if(n<=len)return false;
- t = ELFhash(s[deep]);
- if(!hash[t]) hash[t]=true;
- else return false;
- if(impossible(s[deep],n)) return false;
- s[deep+1][n-3] = 0;
- for(o = 1; o < n-1; ++o)
- if(s[deep][o]=='O')
- {
- for(c = 0; c < o; ++c)
- {
- if(c>0) s[deep+1][c-1] = s[deep][c-1];
- if(s[deep][c]=='C')
- for(w = n-1; w > o; --w)
- {
- if(w<n-1 && w-2>=0) s[deep+1][w-2] = s[deep][w+1];
- // hint: if(w<n-1 && w-2>=0) w-2!!
- if(s[deep][w]=='W')
- {
- t = c;
- for(i = o+1; i < w; ++i) s[deep+1][t++] = s[deep][i];
- for(i = c+1; i < o; ++i) s[deep+1][t++] = s[deep][i];
- if( ok(deep+1,n-3) ) return true;
- }
- }
- }
- }
- return false;
- }
- bool all_in_code(char *s, int n)
- {
- int i, j;
- for(i = len-1; i >= 0; --i)
- {
- for(j = i+1; j <= len; ++j)
- {
- ch = code[j];
- code[j] = 0;
- code_hash[ELFhash(code+i)] = true;
- code[j] = ch;
- }
- }
- for(i = 0; i < n; ++i) str_cnt[s[i]]++;
- for(i = 0; i < len; ++i) code_cnt[code[i]]++;
- for(ch = 'A'; ch <= 'z'; ++ch)
- if(ch!='C' && ch!='O' && ch!='W' && code_cnt[ch]!=str_cnt[ch])
- {
- printf("%c %d %d/n", ch, code_cnt[ch],str_cnt[ch]);
- return 0;
- }
- return 1;
- }
- int main()
- {
- int n;
- freopen("cryptcow.in", "r", stdin);
- freopen("cryptcow.out","w",stdout);
- gets(s[0]);
- n = strlen(s[0]);
- if( (n-len)%3==0 && all_in_code(s[0],n) && ok(0,n) )
- {
- int ans=0;
- for(p=s[0];*p;++p) if(*p=='C')++ans;
- printf("%d %d/n", 1,ans);
- }
- else puts("0 0");
- return 0;
- }