开始做的时候就想到是搜索...写完了样例就跑过了..然后提交就超时..后来再一想..裸搜时间复杂度高得惊人阿..做了几个优化..还是N久跑不出结果...我以为搜索是搜不过的...就想用其他方法来解决..但纠结了很久也没有个明确方向..
写了一天..实在是没辙了..就去网上搜了下解题报告..发现其实是搜索~~关键还是在于剪枝~~~我原来的搜索剪枝真是弱爆了..
1.C.O.W这三个字符任意两个中间的无C.O.W的字符串一定要是原串的子串才合法..因为在后面做任何变化这一段都是改变不了的了..
2.差不多和上面那个一个意思..就是最前面没有任何C.O.W的一截必须和原串的前面这截相等..尾部一样..同上理..
3.C.O.W这些字符出现在最左边的一定是C,出现在最右边的一定是W..
4.在DFS过程中会有很多重复的搜索..这里就要通过Hash来判重..我的Hash方法..见我的Turn函数..自创的说..
5.很诡异的..在别人那看到的..想不出有什么道理..但却是速度提升很多..或许是题目数据的特殊所至~~
先确定O..再确定C..再确定W...在确定W时从后往前扫~~
还有就是字符串用char[]来处理比string来处理速度至少快3倍阿~~
这道题用了几个以前很少用到的字符串函数,这次也熟悉了下...如
strcmp(s1,s2)是比较两串..当且仅当strcmp的返回值是0的时候s1与s2相等...
strncat(s1,s2,k)将s2的前k位加到s1的后面..如果要中间的一段..strncat(s1,s2+i,j)就行了
Program:
/*
ID: zzyzzy12
LANG: C++
TASK: cryptcow
*/
#include<iostream>
#include<istream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stack>
#include<map>
#include<algorithm>
#include<queue>
#define oo 2000000000
#define ll long long
#define pi (atan(2)+atan(0.5))*2
using namespace std;
char str[50]="Begin the Escape execution at the Break of Dawn",s[305];
int lenstr=strlen(str),x,Prime[505],num;
string ss1=str;
bool f,hash[500005];
int Turn(char *s)
{
int i,k=0,l=strlen(s);
s[l]='a';
for (i=0;i<l;i++)
{
k+=Prime[i+1]*s[i]*(s[i]+s[i+1]);
k%=500000;
}
s[l]='\0';
return k;
}
void DFS(char *s,int p)
{
int i,j,k,t,l=strlen(s);
char s1[305];
x=Turn(s);
if (hash[x]) return;
hash[x]=true;
if (!strcmp(s,str))
{
f=true;
printf("1 %d\n",p);
return;
}
//-------------------判断末尾一截是否相等------------------
t=lenstr; i=l;
while (s[i]!='C' && s[i]!='O' && s[i]!='W')
{
if (s[i]!=str[t]) return;
t--; i--;
}
if (s[i]!='W') return;
//------------------判断前面一截是否相等-------------------
i=0;
while (s[i]!='C' && s[i]!='O' && s[i]!='W')
{
if (s[i]!=str[i]) return;
i++;
}
if (s[i]!='C') return;
//-------------判断C,O,W中间的串是否在所求串中存在---------
s1[0]='\0';
for (i++;i<l;i++)
if (s[i]=='C' || s[i]=='O' || s[i]=='W')
{
if (ss1.find(s1)==-1) return;
s1[0]='\0';
}else strncat(s1,s+i,1);
//-----------------------------------------
for (j=0;j<l;j++)
if (s[j]=='O')
for (i=0;i<j;i++)
if (s[i]=='C')
for (k=l-1;k>j;k--)
if (s[k]=='W')
{
s1[0]='\0';
strncat(s1,s,i);
strncat(s1,s+j+1,k-j-1);
strncat(s1,s+i+1,j-i-1);
strncat(s1,s+k+1,l-k-1);
DFS(s1,p+1);
if (f) return;
}
}
int main()
{
freopen("cryptcow.in","r",stdin);
freopen("cryptcow.out","w",stdout);
gets(s);
while (s[strlen(s)-1]==' ') s[strlen(s)-1]='\0';
f=false;
memset(hash,false,sizeof(hash));
num=0;
for (int i=3;i>0;i++)
{
for (int j=2;j*j<=i;j++)
if (i%j==0) goto A;
Prime[++num]=i;
if (num==500) break;
A: ;
}
DFS(s,0);
if (!f) printf("0 0\n");
return 0;
}