好吧,在比赛的时候最后20分钟才看这道题目,当时的想法是既然数据量有100000,而且又只给1000ms,那么应该是O(n)的算法了,当时就想到了利用递推。。。可是没有去写,也许是没有仔细的考虑清楚吧,最终也是比赛之后才写出来。。。
在后来解决这道题目的时候我还是用了一点小技巧。。不然会爆内存的,用了一个滚动数组,因为我们可以很明显的看出来,当一个新的字符串加入的时候,我们的答案变化仅仅是由新加入的字符串和之前的尾部的字符串共同决定的。另外一个我用的很多的小技巧就是让一个变量在0和1之间不断的来回变动,x = 1 - x 这条语句可是使得x 在0到1之间不断的往返,来作为我的数组下标。
总体思路就是不断的读取一个新的字符串,来和之前的尾部字符串相比较,从而决定答案,check函数接受4个参数,第一个是第 i 个字符串 ,第二个是第 i - 1个字符串,第三个和第四个参数表示 i 和 i -1是否反转,初始化的时候数组里面有一个空串,假若一条路走不通了,就赋值为无穷大,同时跳过和答案为无穷大的字符串的比较,com是自己手写的比较函数,以下是代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
using namespace std;
const long long inf=LLONG_MAX-0x3f3f3f3f;
char arr[2][50005];
long long ans[2][2];
int cost[100005],n;
bool check(int i),com(char* si, char* si_1,bool si_reverse,bool si_1_reverse),flag[4];;
int main(){
arr[0][0]=arr[0][1]=0;
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&cost[i]);
for(int i=1;i<=n;++i){
scanf("%s",arr[i&1]);
if(!check(i)){
printf("%d\n",-1);
return 0;
}
}
printf("%lld\n",min(ans[n&1][0],ans[n&1][1]));
return 0;
}
bool check(int i){
memset(flag,0,sizeof(flag));
ans[i&1][0]=ans[i&1][1]=inf;
if(ans[1-(i&1)][0]!=inf&&com(arr[i&1],arr[1-(i&1)],false,false)){
flag[0]=true,ans[i&1][0]=ans[1-(i&1)][0];
}
if(ans[1-(i&1)][1]!=inf&&com(arr[i&1],arr[1-(i&1)],false,true)){
flag[1]=true,ans[i&1][0]=min(ans[i&1][0],ans[1-(i&1)][1]);
}
if(ans[1-(i&1)][0]!=inf&&com(arr[i&1],arr[1-(i&1)],true,false)){
flag[2]=true,ans[i&1][1]=ans[1-(i&1)][0]+cost[i];
}
if(ans[1-(i&1)][1]!=inf&&com(arr[i&1],arr[1-(i&1)],true,true)){
flag[3]=true,ans[i&1][1]=min(ans[i&1][1],ans[1-(i&1)][1]+cost[i]);
}
if(!(flag[0]||flag[1]||flag[2]||flag[3]))
return false;
return true;
}
bool com(char* si, char* si_1,bool si_reverse,bool si_1_reverse){
int a =strlen(si),b=strlen(si_1),i,k;
if(b==0)
return true;
if(!si_reverse&&!si_1_reverse){
return strcmp(si,si_1)>=0;
}
else if(!si_reverse&&si_1_reverse){
for(i=0,k=b-1;i<a&&k>=0;++i,--k)
if(si[i]<si_1[k])
return false;
else if(si[i]>si_1[k])
return true;
if(i>=a&&k>=0)
return false;
return true;
}
else if(si_reverse&&!si_1_reverse){
for(i=a-1,k=0;i>=0&&k<b;--i,++k)
if(si[i]<si_1[k])
return false;
else if(si[i]>si_1[k])
return true;
if(i<0&&k<b)
return false;
return true;
}
else{
for(i=a-1,k=b-1;i>=0&&k>=0;--i,--k)
if(si[i]<si_1[k])
return false;
else if(si[i]>si_1[k])
return true;
if(i<k)
return false;
return true;
}
}
(其实写的这么长我自己都不敢看。。。)