zoukankan      html  css  js  c++  java
  • BZOJ3670 [Noi2014]动物园[KMP]

    这是noi题吗。。为什么我这种菜鸡都会做。。表示质疑。

    求一个串$S$的每一个前缀$i$的不重叠的既为前缀又为后缀(下简称:border)的子串数量$num$。

    模仿KMP,假设当前在求$i$的$next$数组,同时希望求出$num$,那也就是看前缀$i-1$中是border且不重叠的所有子串和第$i$位的匹配数量。

    那么可以从最长的一个不超过$lfloor i/2 floor$的border开始比对,可以匹配就$++num$,然后继续跳(也就是$k=next[k]$)。

    这里类似于KMP的自匹配,只不过将$j$要求为不超过串长一半$k$来匹配。

    看了$N leq 1000000$,应当是线性的,尝试寻找递推方法。

    自己瞎画了个图。现在期望寻找递推关系。橙色是不超过$lfloor i/2 floor$的能成功匹配的border。

    $k$是不超过串长一半的最长border,$j$是最长border(无限制,就是原KMP的)

    发现图中三个红色框框柱的串都是等价的。这意味着我如果要求:有多少个像图中一样最左最右两个红框相等的。

    通过上述转化,发现就是要求前缀$k+1$里面有多少可重叠的border。设之为$g[k+1]$。

    那么$num=g[k+1]$。于是就成功了。

    下面看怎么推$g[i]$。发现最长border$j$的$g[j]$有多少相等的子border,$g[i]$就有多少,还要再加上本身全串的一个$1$。可以用类似上面那个图的方法来等价。

    于是就做一次KMP,每匹配一位时候同时让$j$和$k$跳$next$至满足要求,并进行匹配和递推。详见code。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define dbg(x) cerr << #x << " = " << x <<endl
     7 using namespace std;
     8 typedef long long ll;
     9 typedef double db;
    10 typedef pair<int,int> pii;
    11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    16 template<typename T>inline T read(T&x){
    17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    19 }
    20 const int N=1e6+7,P=1e9+7;
    21 char s[N];
    22 int nxt[N],f[N],g[N];
    23 int T,ans;
    24 
    25 int main(){//freopen("1.in","r",stdin);freopen("1.ans","w",stdout);
    26     read(T);while(T--){
    27         scanf("%s",s+1);
    28         nxt[1]=f[1]=0;ans=g[1]=1;
    29         int j=0,k=0,n=strlen(s+1);
    30         for(register int i=2;i<=n;++i){
    31             while(j&&s[i]^s[j+1])j=nxt[j];
    32             while(k&&(s[i]^s[k+1]||k>=(i>>1)))k=nxt[k];
    33             nxt[i]=s[i]==s[j+1]?++j:0;
    34             (s[i]==s[k+1])&&(++k);
    35             f[i]=g[k];
    36             g[i]=g[j]+1;
    37             ans=ans*1ll*(f[i]+1)%P;
    38         //    dbg(i),dbg(j),dbg(k),dbg(f[i]);
    39         }
    40         printf("%d
    ",ans);
    41     }
    42     return 0;
    43 }
    View Code
  • 相关阅读:
    关于数据库的索引知识
    RESTful API设计相关
    Coroutine(协程)模式与线程
    Python网络编程中的服务器架构(负载均衡、单线程、多线程和同步、异步等)
    读懂diff
    Linux学习笔记——如何使用echo指令向文件写入内容
    ubuntu中执行定时任务crontab
    网络编程之异步IO,rabbitMQ笔记
    走进docker的世界之入门篇
    xml基础
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11504831.html
Copyright © 2011-2022 走看看