hdu 4333 kmp+扩展kmp

第一个问题,如何比较新生成的数与原数的大小?

比较相同位数的数的大小,从最高位到最低位一位一位比较,如果每一位数都相等,那么这两个数相等;否则找到第一位不相同的数,比较该数大小,该数大的原数大,该数小的原数小;

那么,我们需要一位一位比较,

那么如果前缀是一样的话我们就可以不去比较直接比较不相同的那一位即可

显然,这是扩展kmp所解决的问题

那么我们将数字转化为字符串处理,len为原数的长度

那么,我们就用扩展kmp中的next数组(程序中的extend_next数组)来进行判断:

1、相等:extend_next[i]>=len

2、新数大于原数:s[extend_next[i]+1]<s[i+extend_next[i]] (找到第一个不相等位)

3、新数小于原数:s[extend_next[i]+1]>s[i+extend_next[i]] (找到第一个不相等位)

注意:如果原串是以一个循环节重复所得,令循环节长度为tt。那么最后的结果全部除以tt即可,所以用kmp求循环节


第一道扩展kmp题,各种边界和下标细节和崩溃 orz,三节课就这样过去了 orz

细节:【1】在while里判断相等时,一定要先保证下标不超过len,然后再进行比较不然各种崩溃(while套if-break)

           【2】判断原串是否是循环节重复得到时,用 len mod tt判断,要对tt=0判断是否为0不然会除0→_→


var
        t,l,e,g,c,len,tt :longint;
        i,j              :longint;
        s                :ansistring;
        next,extend_next :array[0..200010] of longint;
procedure kmp;
var
        p,l1:longint;
        i:longint;
begin
   p:=0;l1:=len;
   for i:=2 to l1 do
   begin
      while (p<>0) and (s[i]<>s[p+1]) do p:=next[p];
      if s[i]=s[p+1] then
      begin
         inc(p);
         next[i]:=p;
      end else next[i]:=0;
   end;
end;

procedure get_next;
var
        p,a,l,len:longint;
        k,j:longint;
begin
   len:=length(s);
   extend_next[1]:=len;a:=0;
   while (a+2<=len) do
    if (s[a+1]=s[a+2]) then inc(a) else break;
   extend_next[2]:=a;a:=2;
   //
   for k:=3 to len do
   begin
      p:=a+extend_next[a]-1;
      l:=extend_next[k-a+1];
      if (k+l-1<p) then extend_next[k]:=l else
      begin
         if p-k+1<0 then j:=0 else j:=p-k+1;
         while (k+j<=len) and (j+1<=len) do
          if (s[k+j]=s[j+1]) then inc(j) else break;
         extend_next[k]:=j;
         if k+extend_next[k]-1>p then a:=k;
      end;
   end;
end;

begin
   //assign(input,'date.in');reset(input);
   //assign(output,'2.out');rewrite(output);
   readln(t);
   for j:=1 to t do
   begin
      fillchar(next,sizeof(next),0);
      fillchar(extend_next,sizeof(extend_next),0);
      readln(s);
      len:=length(s);
      kmp;
      tt:=len-next[len];
      if (tt=0) then tt:=4 else
       if (len mod tt=0) then tt:=len div tt else tt:=1;
      //
      s:=s+s;
      get_next;
      e:=0;l:=0;g:=0;
      for i:=1 to len do
      begin
         if (extend_next[i]>=len) then inc(e) else
          if (s[extend_next[i]+1]>s[i+extend_next[i]]) then inc(l) else
           if (s[extend_next[i]+1]<s[i+extend_next[i]]) then inc(g);
      end;
      //
      writeln('Case ',j,':',' ',l div tt,' ',e div tt,' ',g div tt);
   end;
   //close(input);close(output);
end.
——by Eirlys

转载请注明出处=w=


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值