??xml version="1.0" encoding="utf-8" standalone="yes"?>久久精品国产免费一区,久久er99热精品一区二区,少妇人妻88久久中文字幕http://www.shnenglu.com/MatoNo1/archive/2012/10/24/193781.htmlMato_No1Mato_No1Wed, 24 Oct 2012 07:11:00 GMThttp://www.shnenglu.com/MatoNo1/archive/2012/10/24/193781.htmlhttp://www.shnenglu.com/MatoNo1/comments/193781.htmlhttp://www.shnenglu.com/MatoNo1/archive/2012/10/24/193781.html#Feedback0http://www.shnenglu.com/MatoNo1/comments/commentRss/193781.htmlhttp://www.shnenglu.com/MatoNo1/services/trackbacks/193781.html原题地址
本沙茶在2009q?月曾l在k-i+1}, i<=k<jQ第二项需要满_字符串[i..j]q一D|好由[i..k]q一D늚若干ơ复制得到}
Q加上k-i+1是因为对于以下三U重叠字W串Q不压羃比压~要短:(x)AA型、AAA型、ABAB型)
边界QF[i][i]=1Q?br />
问题是在上述方程的第二项里如何求出可行的k。显Ӟ只需要对[i..j]q一D作exKMPQ求出nxQ然后k可行当且仅当满Q(1Qnx[k+1]=j-kQ(2Q?k-i+1)|(j-i+1)Q?br />
不过Q本题在写exKMP的过E中?x)出现很囧的问?#8230;…׃下标不是?开始,而是从i开始,所以很多地方关于下标的计算都要Ҏ(gu)Q非怸方便Q而且很容易疵掉。与其这Pq不如把[i..j]q一D复制到一个新字符串里Q下标从0开始。对于其它的某些字符串算法和数据l构Q或怹是这样囧……

代码Q?br />
#include <iostream>
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<string.h>
using namespace std;
#define re(i, n) for (int i=0; i<n; i++)
#define re1(i, n) for (int i=1; i<=n; i++)
#define re2(i, l, r) for (int i=l; i<r; i++)
#define re3(i, l, r) for (int i=l; i<=r; i++)
#define rre(i, n) for (int i=n-1; i>=0; i--)
#define rre1(i, n) for (int i=n; i>0; i--)
#define rre2(i, r, l) for (int i=r-1; i>=l; i--)
#define rre3(i, r, l) for (int i=r; i>=l; i--)
#define ll long long
const int MAXN = 110, INF = ~0U >> 2;
int n, F[MAXN][MAXN], nx[MAXN], res;
char ss[MAXN + 1], ss0[MAXN + 1];
void init()
{
    scanf(
"%s", ss); n = strlen(ss);
}
int sol0(int l, int r)
{
    
int W = r - l + 1; re3(i, l, r) ss0[i - l] = ss[i];
    nx[
0= W; nx[1= nx[0- 1; re(i, W) if (ss0[i] != ss0[i + 1]) {nx[1= i; break;}
    
int k = 1, len, p = k + nx[k] - 1, x, y;
    re2(i, 
2, W) {
        len 
= nx[i - k];
        
if (i + len <= p) nx[i] = len; else {
            x 
= p + 1; y = p - i + 1if (y < 0) {x++; y = 0;}
            
for (; x<=&& ss0[x]==ss0[y]; x++, y++) ;
            nx[i] 
= y; k = i; p = i + y - 1;
        }
    }
    
int res0 = INF, tmp, V;
    re2(i, 
1, W) if (!(W % i) && nx[i] == W - i) {
        V 
= F[l][l + i - 1+ 2; tmp = W / i; while (tmp) {tmp /= 10; V++;}
        
if (W < V) V = W;
        
if (V < res0) res0 = V;
    }
    
return res0;
}
void solve()
{
    re(i, n) F[i][i] 
= 1;
    
int j, tmp;
    re2(x, 
1, n) re(i, n-x) {
        j 
= i + x; F[i][j] = sol0(i, j);
        re2(k, i, j) {tmp 
= F[i][k] + F[k + 1][j]; if (tmp < F[i][j]) F[i][j] = tmp;}
    }
    res 
= F[0][n - 1];
}
void pri()
{
    printf(
"%d\n", res);
}
int main()
{
    init();
    solve();
    pri();
    
return 0;
}


Mato_No1 2012-10-24 15:11 发表评论
]]>
COCI 2011?012 #5 后两题题?/title><link>http://www.shnenglu.com/MatoNo1/archive/2012/04/18/171899.html</link><dc:creator>Mato_No1</dc:creator><author>Mato_No1</author><pubDate>Wed, 18 Apr 2012 12:26:00 GMT</pubDate><guid>http://www.shnenglu.com/MatoNo1/archive/2012/04/18/171899.html</guid><wfw:comment>http://www.shnenglu.com/MatoNo1/comments/171899.html</wfw:comment><comments>http://www.shnenglu.com/MatoNo1/archive/2012/04/18/171899.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/MatoNo1/comments/commentRss/171899.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/MatoNo1/services/trackbacks/171899.html</trackback:ping><description><![CDATA[<a title="相关链接" href="http://www.shnenglu.com/MatoNo1/archive/2012/03/18/168229.html">相关链接</a><br />今天在回以前的题目的时候,U然发现COCI 2011?012 #5的后两题q犇题(臛_一般h可以捉的Q?#8230;…是我当时惛_掉了?#8230;…<br /><br />blokoviQ?br />首先很容易发现最优方案必然是从顶到底Q先量往双放,攑ֈ某一个{折点处再量往左边?#8230;…<br />然后是枚Dq个转折点,q一下就行了Q暴力O(N<sup>2</sup>)的可以过7个点Q本沙茶现场赛时是用这个的Q?#8230;…<br />优化Q可以从上到下依ơ枚举{折点Q设目前的{折点为iQ则在下一ơ枚举时Q?i+1){折点Q,?i+1)往叛_^U?单位Q然后根据那个重心计公式可以得出,W?i+2)个及(qing)以后的必然是整体向右q移(2*m2)/(m1+m2)Q其中m1为前i个的质量和,m2为第(i+1)个的质量……在此基础上维护{折点前重心位|、{折点的重心的横坐标(相对于最上面的那个)以及(qing)最下面的那个的重心的横坐标Q相对于最上面的那个)p了(注意转折Ҏ(gu)W一个或最后一个的Ҏ(gu)情况要单独处理)Q时间复杂度O(N)?br /><br />poplocavanjeQ?br />其实q题只要用AC自动机随便ؕ搞一下就行了……Trie上的每个l点l护一个KKQ表Cl点所代表的字W串的后~的最大匹配长度(当然前提条g是该l点是危险的Q,则:(x)Q?Q若该结Ҏ(gu)来就代表一个待匚w的子Ԍ则KKgؓ(f)子串长度Q(2Q若该结Ҏ(gu)通过p|指针上溯C个危险结点的Q则该结点的KK是上溯到的那个危险l点的KK。然后做一ơ匹配,C所有的匚w区间Q再求出未被区间覆盖的总长度(排序+扫描卛_Q不需M数据l构Q就行了?br /><br />注意几个易疵的地方:(x)<br />Q?QTrie的大要开?M才能q(不过再大pMLE了囧……Q;<br />Q?Q在动机计算KK的时候,如果一个结Ҏ(gu)来就是危险的Q即上述W?U结点)Q此q程中又发现它是上述W?U结点,?strong><span style="color: #ff0000;">?/span><span style="color: red;">能重新计KK</span></strong>Q?br />Q?Q最后求未被区间覆盖总长度的Ҏ(gu)Q先C所有的区间Q按照先左端炚w增序后右端炚w增序排序,当中L被别的区间覆盖的区间Q然后先看一下排序后的第一个区间和最后一个区_(d)得出W一个区间之前与最后一个区间之后的未被覆盖的部分,中间的扫描求解时Q如果某区间的左端点大于(前一区间的右端点+1)Q则计入中间的空?#8230;…不过q有一U方法就是不L被别的覆盖的区间Q而是在扫描过E中l护右端Ҏ(gu)大值maxrQ然后把上面Ҏ(gu)中的所有右端点改ؓ(f)maxr卛_?br /><br />代码Q?br /><a title="blokovi" >blokovi</a> <a title="poplocavanje" >poplocavanje</a><img src ="http://www.shnenglu.com/MatoNo1/aggbug/171899.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/MatoNo1/" target="_blank">Mato_No1</a> 2012-04-18 20:26 <a href="http://www.shnenglu.com/MatoNo1/archive/2012/04/18/171899.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>KMP、AC自动机在字符串匹配类动态规划问题中的应?/title><link>http://www.shnenglu.com/MatoNo1/archive/2011/10/30/159339.html</link><dc:creator>Mato_No1</dc:creator><author>Mato_No1</author><pubDate>Sun, 30 Oct 2011 03:22:00 GMT</pubDate><guid>http://www.shnenglu.com/MatoNo1/archive/2011/10/30/159339.html</guid><wfw:comment>http://www.shnenglu.com/MatoNo1/comments/159339.html</wfw:comment><comments>http://www.shnenglu.com/MatoNo1/archive/2011/10/30/159339.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/MatoNo1/comments/commentRss/159339.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/MatoNo1/services/trackbacks/159339.html</trackback:ping><description><![CDATA[有一cd态规划(其中也包含递推Q问题,要求满一些限制条件的字符Ԍq些限制条g?#8220;需要含有某个子?#8221;?#8220;不能含有某个子串”Q那么KMP、AC自动机等有大用了?br /><br />【例1?a title="HDU3689" >HDU3689</a><br />题意Q字W集中有一些字W,l出每个字符的出现概率(它们的和保证?Q,再给Z个子串BQ求QQl一个长度ؓ(f)N的字W串AQ只能包含字W集中的字符Q,使得S是A的子串的概率?br /><br />求解q类问题首先要进行补集{化。因为子串可能有重叠Q比?ababa"中就出现了两?aba"Q,所以先转化?#8220;求Ql一个长度ؓ(f)N的字W串AQ只能包含字W集中的字符Q,使得<span style="color: red"><strong>B不是A的子?/strong></span>的概?#8221;Q然后再?减去q个概率即ؓ(f)l果?br />设F[i][j]?#8220;在所有长度ؓ(f)i?span style="color: red"><strong>不出现B</strong></span>的字W串中,后缀与B的前~匚w长度为jQ即该字W串的后~与B的前~?span style="color: red"><strong>最?/strong></span>匚w长度为jQ的概率”Q很昄QF是由递推得到了,关键是如何进行状态{U?或者说Q在递推q程中,哪些状态可能成为F[i][j]的前状态?<br />假设F[i-1][k]是F[i][j]的前状态,也就是说Q?span style="color: red"><strong>在字W集中至存在一个字WcQ得主串的Wi位(最后一位)取cӞ能够从F[i-1][k]转移到F[i][j]</strong></span>。这需要求一个值S[k][c]Q表C当M的后~与B的前~的(最大)匚w长度为kӞ在主串后再加上一个字WcQ其匚w长度?x)变成什么。D例:(x)讄前主串A'="abasab"QB="asabs"Q其匚w长度?Q若在A'后加上一个字W?s'Q则匚w长度变ؓ(f)5Q所以S[4]['s']=5Q而若在A'后加上一个字W?a'Q则匚w长度?x)变?Q所以S[4]['a']=1。显然S值和A前面的哪些字W是没有关系的?br />那么q个S值如何计?其实可以发现QS和KMP法中的nx数组似Q因此完全可以按照计nx数组的办法来计算S。具体来_(d)先要对B作KMP自n匚wQ求出其nx数组Q然后,在求S[k][c]的时候,试在B的第k位(׃B的下标从0开始所以B[k-1]Q后加上字符cQ看看会(x)“回退”到哪里即可。代码:(x) <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">     </span><span style="color: #0000ff">int</span><span style="color: #000000"> j </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">0</span><span style="color: #000000">; nx[</span><span style="color: #000000">0</span><span style="color: #000000">] </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">0</span><span style="color: #000000">;<br />     re2(i, </span><span style="color: #000000">1</span><span style="color: #000000">, m) {<br />            </span><span style="color: #0000ff">while</span><span style="color: #000000"> (j </span><span style="color: #000000">&&</span><span style="color: #000000"> A[i] </span><span style="color: #000000">!=</span><span style="color: #000000"> A[j]) j </span><span style="color: #000000">=</span><span style="color: #000000"> nx[j </span><span style="color: #000000">-</span><span style="color: #000000"> </span><span style="color: #000000">1</span><span style="color: #000000">];<br />            </span><span style="color: #0000ff">if</span><span style="color: #000000"> (A[i] </span><span style="color: #000000">==</span><span style="color: #000000"> A[j]) j</span><span style="color: #000000">++</span><span style="color: #000000">;<br />            nx[i] </span><span style="color: #000000">=</span><span style="color: #000000"> j;<br />     }<br />     re(i, m) re(k, SZ) {<br />           j </span><span style="color: #000000">=</span><span style="color: #000000"> i;<br />           </span><span style="color: #0000ff">while</span><span style="color: #000000"> (j </span><span style="color: #000000">&&</span><span style="color: #000000"> A[j] </span><span style="color: #000000">!=</span><span style="color: #000000"> k </span><span style="color: #000000">+</span><span style="color: #000000"> </span><span style="color: #000000">97</span><span style="color: #000000">) j </span><span style="color: #000000">=</span><span style="color: #000000"> nx[j </span><span style="color: #000000">-</span><span style="color: #000000"> </span><span style="color: #000000">1</span><span style="color: #000000">];<br />           </span><span style="color: #0000ff">if</span><span style="color: #000000"> (A[j] </span><span style="color: #000000">==</span><span style="color: #000000"> k </span><span style="color: #000000">+</span><span style="color: #000000"> </span><span style="color: #000000">97</span><span style="color: #000000">) S[i][k] </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">++</span><span style="color: #000000">j; </span><span style="color: #0000ff">else</span><span style="color: #000000"> S[i][k] </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">0</span><span style="color: #000000">;<br />     }</span></div>q里m是B的长度。注意,当i=mӞS[i][j]是无意义的,因ؓ(f)前面已经说过了不能出现B?br />在求出S值后p求出Fg。对于状态F[i][j]Q若存在一个字Wc使得x=S[i][c]Q满?<=x<mQ,则F[i][j]是F[i+1][x]的前状态。当Ӟ׃本题是求概率而不是求LQ且每个字符出现的概率还不一P所以{Uȝ时候,应是F[i+1][x]加上F[i][j]*P[c]QP[c]是字Wc出现的概率)Q边界:(x)F[0][0]=1QF[0][1..m-1]均ؓ(f)0?br />最l结果ؓ(f)1-∑F[N][0..m-1]?br /><br /><a title="代码" >代码</a><br /><br />【例2?a title="PKU1625" >PKU1625</a>Q?a title="URAL1158" >URAL1158</a>Q?br />题意Q给Z些子Ԍ求长度ؓ(f)NQ各个字W都属于l定的字W集的所有字W串中,不包含Q何一个给出的子串的字W串个数Q需要用压9位的高精度)?br /><br />本题昄是【例1】的多子串Ş式,而用来解军_个字W串同时匚w的只有AC自动机,那么如何在本题中使用AC自动机求解呢Q?br />观察【例1】中的F[i][j]Q可以想象一下,一个图中有m个顶点,分别表示匚w长度?..(m-1)Q然后不断新加入的字W让q些状态在q些l点间不断{U(状态{Ud是图中的边)Q这PF[i][<span>j]pC?#8220;阶段i到达l点j?#8221;。而AC自动</span><span>机是ZTrieQ树(wi)Q的Q?/span><span>其中有现?/span><span>的结</span><span>点,q就揭示了本题的?/span><span>?/span><span><strong>Q?/strong></span><br /><span>F[i][j]</span><span>?/span><span>C?/span><strong><span style="color: #ff0000">长度为i的合法的字符Ԍ是满字符集限制且不包含Q何一个给定子Ԍ中,在匹配到最后一位(</span></strong><strong style="color: #ff0000">Wi位)后,刚好到达l点j的字W串?/strong><strong style="color: #ff0000">个数</strong>?br />同样QS[k][c]表示“目前到达l点kQ接下来的一个字W是c的时候,?x)到辑֓个结炏V在Ҏ(gu)有的子串建立了自动机之后QS值只要类似地搞就能求出来了。然后F的{UM搞定了?br />不过Q本题要万分注意AC自动机的一个BUGQ在建立了自动机以后Q需要把所有本w不危险Q如果一个结点代表的字符串刚好是某一个给出的不能出现的子Ԍ则该l点是危险结点)Q但通过p|指针不断上溯能够到达一个危险结点的l点Q也标记为危险结点,比如两个子串?abcde"?bc"Q则代表"abcd"的那个结点由于包含了"bc"所以也是危险的?br />此外Q本题的输入要注意,字符集的ASCII码范围是-128~127Q所以必ȝchar而不是unsigned charQ且׃可能包含I格所以必ȝgets()而不是scanf()输入Q又因ؓ(f)C/C++中木有负C标,因此在输入之后还要{化一下(?28Q?br /><br /><a title="代码" >代码</a><br /><br />【例3?a title="PKU3691" >PKU3691</a><br />题意Q给Z些子串和一个字W串AQ其每个字符均属于字W集{'A', 'C', 'G', 'T'}Q,求至要改动A的几个字W(不能Ҏ(gu)不属于字W集的字W)Q得它不包含Q何一个给出的子串Q若不管怎么攚w不行Q则l果?1?br /><br />q就是真正的DP了。设F[i][j]为前i位,到达的结点ؓ(f)jQ最改动的字符个数Q则转移方程?br />F[i][j] = min{F[i-1][x] + (A[i] != c)}Qc∈{'A', 'C', 'G', 'T'}QS[x][c]=j。边界:(x)F[0][root]=0Q其余的F[0][]=+∞QA的实际下标从1开始?br />求S数组的方法见【例2?br /><br /><a title="代码" >代码</a><br /><br />【例4?a title="PKU3208" >PKU3208</a><br />题意Q含有连l的三个数字6的正整数Q称?beastly number"Q求WP个(1<=P<=50000000Q?beastly number"Q其位数不会(x)过15位)?br />Q这题是本沙茶在PKU上至今ؓ(f)止,自己惛_法的AC人数最的题)<br />本题其实是用不着KMP的,因ؓ(f)"666"q样单的子串……<br /><br />思\Q由于位C?x)超q?5位(后来发现最多只?0位)Q所以每?beastly number"都可以看成一个长度ؓ(f)15Q字W集为['0'..'9']的字W串Q注意是可以有前?的,因ؓ(f)位数可能不15位)AQ整个过E也是从高位(W?位)向低位(W?4位)求出A的各位?br /><br />预处理:(x)求出F[i][j]Q表CA的前i位已l确定(其中不含"666"Q准来说是非末不?666"Q,且前i位的末尾刚好有j?6'Qj的范围是0?Q时Q有多少?beastly number"Q注意,前i位既然已l确定,׃可更改了Q能够决定的只有Wi位的后面Q?br />昄先要求出F0[i][j]表示有多个不是"beastly number"。其递推方程不好写,见代码(其实也是很好理解的)。然后F[i][j]=10<sup>14-i</sup> - F0[i][j]?br /><br />然后是不断调整边界来构造了。准来_(d)讑։i-1位已l确定,现在要确定第i位,则枚丄i位是0~9中的哪个|然后求出满条g的最的"beastly number"和最大的"beastly number"的名ơ(注意Q名ơ是?开始的Q,看看P在不在其中,q样p定了。严重注意:(x)如果已确定的位数中已l出C"666"Q接下来的就不用枚D了,直接在后面接上P-Lp了,L为左边界?br /><br />但是Qؓ(f)什么要把本题放在KMP的专题里面呢囧?<span>因ؓ(f)如果q个子串不是"666"而是一些结构复</span><span>杂的东东比如"123131"q样的,只有借助K</span><span>MP法了。这ӞF[i][j]pC?A的前i位已l确定(非末不含这个子ԌQ且其后~与这个子串的前缀?/span><span>配长度ؓ(f)</span><span>jQ?/span>有多个"beastly number" Q{ULE与前几个例子类伹{?br /><br /><a title="代码" >代码</a><br /><br />ȝQ?br />KMP法和AC自动机的状态{UL质军_了它们在字符串匹配类DP问题中的巨大作用。在实际应用中,要注意灵zM用它们。此外,AC自动机的那个BUG是一定要注意的?<img src ="http://www.shnenglu.com/MatoNo1/aggbug/159339.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/MatoNo1/" target="_blank">Mato_No1</a> 2011-10-30 11:22 <a href="http://www.shnenglu.com/MatoNo1/archive/2011/10/30/159339.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>后缀数组http://www.shnenglu.com/MatoNo1/archive/2011/10/23/158926.htmlMato_No1Mato_No1Sun, 23 Oct 2011 08:51:00 GMThttp://www.shnenglu.com/MatoNo1/archive/2011/10/23/158926.htmlhttp://www.shnenglu.com/MatoNo1/comments/158926.htmlhttp://www.shnenglu.com/MatoNo1/archive/2011/10/23/158926.html#Feedback2http://www.shnenglu.com/MatoNo1/comments/commentRss/158926.htmlhttp://www.shnenglu.com/MatoNo1/services/trackbacks/158926.html
?】一些定义:(x)
字符Ԍ(x)q义的字W串是指“元素cd有序Q且元素值有一定范围的序列”Q其元素不一定非要是字符Q可以是数字{,因此整数、二q制数等也是字符Ԍ
字符集:(x)字符串的元素值的范围UCؓ(f)字符集,其大记为SZ?br />字符串的长度Q字W串中元素的个数Q一般记为NQ长度ؓ(f)N的字W串AW一ơ提到时一般用A[0..N-1]来表C;
前缀Q字W串A[0..N-1]的从A[0]开始的若干个连l的字符l成的字W串UCؓ(f)A的前~Q以?#8220;前缀i”或?#8220;~号为i的前~”指的都是A[0..i]Q?br />后缀Q字W串A[0..N-1]的到A[N-1]l止的若q个q箋的字W组成的字符串称为A的后~Q以?#8220;后缀i”或?#8220;~号为i的后~”指的都是A[i..N-1];

对于一个长度ؓ(f)N的字W串Q将其N个后~按字典序大小q行排序Q得C个数lsa[i]和rank[i]Qsa[i]为排在第i位的后缀的编P也就是一般说的ord[i]Q,rank[i]为排在后~i排在的位|(UCؓ(f)后缀i的名ơ)。sa、rank值的范围均ؓ(f)[0..N-1]。sa和rank互逆,即sa[i]=j{h(hun)于rank[j]=iQ或者说成sa[rank[i]]=rank[sa[i]]=i。这里,saUCؓ(f)后缀数组QrankUCؓ(f)名次数组?br />
?】用倍增法求后~数组Q?br />在论文里Q后~数组有两U求法:(x)倍增法和DC3法Q前者的旉复杂度ؓ(f)O(NlogN)Q但常数较小Q后者的旉复杂度ؓ(f)O(N)Q但常数较大Q在实际应用中,两者的L间相差不大,且后者比前者难理解得多Q本沙茶理解前者都用了几天旉……后者就木敢看了Q。这里就ȝ一下倍增法吧囧……
首先Q脓(chung)一下本沙茶的用倍增法求后~数组的模板:(x)
void suffix_array()
{
    
int p, v0, v1, v00, v01;
    re(i, SZ) S[i] 
= 0;
    re(i, n) rank[i] 
= A[i];
    re(i, n) S[A[i]]
++;
    re2(i, 
1, SZ) S[i] += S[i - 1];
    rre(i, n) sa[
--S[A[i]]] = i;
    
for (int j=1; j<n; j<<=1) {
        p 
= 0; re2(i, n-j, n) tmp[p++= i;
        re(i, n) 
if (sa[i] >= j) tmp[p++= sa[i] - j;
        re(i, SZ) S[i] 
= 0;
        re(i, n) S[rank[i]]
++;
        re2(i, 
1, SZ) S[i] += S[i - 1];
        rre(i, n) sa[
--S[rank[tmp[i]]]] = tmp[i];
        tmp[sa[
0]] = p = 0;
        re2(i, 
1, n) {
            v0 
= sa[i - 1]; v1 = sa[i];
            
if (v0 + j < n) v00 = rank[v0 + j]; else v00 = -1;
            
if (v1 + j < n) v01 = rank[v1 + j]; else v01 = -1;
            
if (rank[v0] == rank[v1] && v00 == v01) tmp[sa[i]] = p; else tmp[sa[i]] = ++p;
        }
        re(i, n) rank[i] 
= tmp[i];
        SZ 
= ++p;
    }
}
q里A是待求sa和rank的字W串?br />
<1>倍增法的思想Q?br />记R[i][j]为A[i..i+2j-1]Q如果越界,则后面用@填充Q在A的所有长度ؓ(f)2j的子Ԍ界则后面用@填充Q中的名ơ(rankQ倹{倍增法是按阶D|出所有R[i][j]的|直到2j>N为止。首先,R[i][0]的就是字WA[i]在A[0..N-1]中的名次Q是可以直接用计数排序来实现的。然后,若R[0..N-1][j-1]已知Q则可以按照以下Ҏ(gu)求出R[0..N-1][j]的|(x)Ҏ(gu)个iQ?<=i<NQ,构造一个二元组<Xi, Yi>Q其中Xi=R[i][j-1]QYi=R[i+2j][j-1]Q若i+2j>=NQ则Yi=-∞Q,然后对这N个二元组按照W一关键字ؓ(f)XQ第二关键字为YQ若两者都相等则判定ؓ(f)相等Q进行排序(可以用基数排序来实现Q,排序后,<Xi, Yi>的名ơ就是的R[i][j]的倹{?br />
<2>一开始,对A中的各个字符q行计数排序Q?
re(i, SZ) S[i] = 0;
re(i, n) rank[i] 
= A[i];
re(i, n) S[A[i]]
++;
re2(i, 
1, SZ) S[i] += S[i - 1];
rre(i, n) sa[
--S[A[i]]] = i;
q个木有马好说的,在搞懂了基数排序之后可以U掉。唯一不同的是q里加了一句:(x)rank[i]=A[i]Q这里的rank[i]是初始的i的名ơ,MS不符合rank[i]的定义和sa与rank间的互逆性。这里就要解释一下了囧。因为在求sa的过E中Qrank值可能不W合定义Q因为长度ؓ(f)2j的子串可能会(x)有相{的Q此时它们的rankg要相{,而sa值由于有下标的限制所以不可能有相{的。因此,在过E中Qrank其实是用来代替A的子串的Q这样rank值只需要表CZ?#8220;相对序”p了,也就是:(x)rank[i0]>(=, <)rank[i1]Q当且仅当A[i0..i0+2j-1]>(=, <)A[i1..i1+2j-1]。这P可以直接A[i]g为初始的rank[i]倹{?br />
<3>jQ代?jQ的g1开始不断倍增Q对二元l进行基数排序求出新阶段的sa|(x)
for (int j=1; j<n; j<<=1) {
    p 
= 0; re2(i, n-j, n) tmp[p++= i;
    re(i, n) 
if (sa[i] >= j) tmp[p++= sa[i] - j;
    re(i, SZ) S[i] 
= 0;
    re(i, n) S[rank[i]]
++;
    re2(i, 
1, SZ) S[i] += S[i - 1];
    rre(i, n) sa[
--S[rank[tmp[i]]]] = tmp[i];
注意q个基数排序的过E是很特别的。首先,它ƈ不是对A在进行排序,而是对上一阶段求出的rank在进行排序。因为前面已l说q,在求sa的过E中Qrank是用来代替A的对应长度的子串的,׃不能直接对子串进行排序(那样的话旉开销很恐怖的Q,所以只能对rankq行排序。另外,q里在对二元l?lt;x, y>的第二关键字QyQ进行排序的q程中加了优化:(x)q些y其实是把上一阶段的sa整体左移了jQ右边空出的部分全部用@Q空Ԍ填充得到的,׃IZ的字典序肯定最,因此右边的IZ按照下标序先写入(f)时saQ代码中用tmp表示的就是(f)时saQ也是对第二关键字y排序后的ordl果Q,然后Q上一阶段的sa如果左移后还木有消失的(也就是sa值大于等于j的)Q再按顺序写入(f)时saQ就得到了排序结果。剩下的对x的排序结果就是上一阶段的saQ唯一不同的是对于x相同的,按照临时名次递增的顺序?br />
<4>求出新阶D늚rank|(x)
tmp[sa[0]] = p = 0;
re2(i, 
1, n) {
    v0 
= sa[i - 1]; v1 = sa[i];
    
if (v0 + j < n) v00 = rank[v0 + j]; else v00 = -1;
    
if (v1 + j < n) v01 = rank[v1 + j]; else v01 = -1;
    
if (rank[v0] == rank[v1] && v00 == v01) tmp[sa[i]] = p; else tmp[sa[i]] = ++p;
}
re(i, n) rank[i] 
= tmp[i];
SZ 
= ++p;
׃下一阶段需要用本阶段的rank|因此在求Z本阶D늚sag后,需要求rank倹{(代码中的tmp起了临时rank的作用,目的是节省空_(d)
因ؓ(f)sa值已l求出,因此只要依次扫描sa可以得到rank|唯一要做的工作就是找到哪些子串是相等的,它们的rank值应该相{,除此之外Qrank值只要依ơ加1卛_。判定相{的Ҏ(gu)Q只需判定rank[i]和rank[i+j]是否都对应相{即可。若rank[i+j]界Q用-∞Q当然Q何一个负数都行,代码中用?1Q来表示?br />最后还有一个优化:(x)׃本阶D늚名次的范围只有[0..p]q么多,下一阶段?#8220;字符?#8221;Q其实就是rank集)的大SZ可以设ؓ(f)p+1Q这样可以省一些时间?br />
q样后缀数组sa和名ơ数lrank全部求完了?br />
以后q有一些更重要的东东就是AC自动机、后~数组{的应用问题Q算了,以后再搞吧囧?br />

Mato_No1 2011-10-23 16:51 发表评论
]]>
AC自动机模杉K——HDU2222http://www.shnenglu.com/MatoNo1/archive/2011/10/19/158635.htmlMato_No1Mato_No1Wed, 19 Oct 2011 11:47:00 GMThttp://www.shnenglu.com/MatoNo1/archive/2011/10/19/158635.htmlhttp://www.shnenglu.com/MatoNo1/comments/158635.htmlhttp://www.shnenglu.com/MatoNo1/archive/2011/10/19/158635.html#Feedback0http://www.shnenglu.com/MatoNo1/comments/commentRss/158635.htmlhttp://www.shnenglu.com/MatoNo1/services/trackbacks/158635.htmlHDU2222Q其实就是一个裸的多串匹配的问题Q给Z个主串和N个子Ԍ求出几个子串在主串中出现q)?br />
我真是太沙茶?#8230;…q么水的题目调了N久,找了N位神犇帮我看代码Q最l才扑և来BUG……

易疵点:(x)
Q?Q本题的子串是可以相同的Q此时Trie的每个结点要设一个mul|表示该结点对应的字符串在所有子串中重复的次敎ͼ另外Q?span style="color: red">不要Z省空间把mul定义成char型,有可能所有的字符串全相同Q因此需要定义成intQ事实证明不?x)爆I间Q,q是本沙茶被折磨了这么久的主要原?/strong>Q?br />Q?QTrie采用静态存储,0L(fng)点作为空l点QNULLQ,因此真正的结点编号从1开始,另外root一般都?L(fng)点;
Q?Q注意在建立自动Z?qing)匹配的时候,所有要沿fail上溯的地方,其边界都?QNULLQ注意不是rootQ或者找C个有对应子结点的l点。注意到0q没有找到的处理Ҏ(gu)Q在建立自动机的时候,T[j]|ؓ(f)rootQ在匚w的时候,x|ؓ(f)rootQ?br />
代码Q模板)Q那些标了Attention的地斚w是易늚Q:(x)
#include <iostream>
#include 
<stdio.h>
#include 
<string>
using namespace std;
using std::string;
#define re(i, n) for (int i=0; i<n; i++)
#define root 1
const int MAXN = 500001, MAXLEN = 1000001, SZ = 26, INF = ~0U >> 2;
struct node {
    
int mul, ch[SZ], fail;    //Attention
} T[MAXN];
int N, Q[MAXN], res;
string s0, A;
char tmp[MAXLEN], tmp0[51];
void ins()
{
    
int len = s0.length(), x = root, c;
    re(i, len) {
        c 
= s0[i] - 97;
        
if (!T[x].ch[c]) {T[x].ch[c] = ++N; T[N].mul = 0; re(j, SZ) T[N].ch[j] = 0;}
        x 
= T[x].ch[c];
    }
    T[x].mul
++;
}
void mkf()
{
    Q[
0= root; T[root].fail = 0;
    
int i, j, x;
    
for (int front=0, rear=0; front<=rear; front++) {
        i 
= Q[front];
        re(k, SZ) 
if (j = T[i].ch[k]) {
            x 
= T[i].fail;
            
while (x && !T[x].ch[k]) x = T[x].fail;        //Attention
            if (x) T[j].fail = T[x].ch[k]; else T[j].fail = root;    //Attention
            Q[++rear] = j;
        }
    }
}
void solve()
{
    
int len = A.length(), x = root, y, c; res = 0;
    re(i, len) {
        c 
= A[i] - 97;
        
while (x && !T[x].ch[c]) x = T[x].fail;    //Attention
        if (!x) x = root; else x = T[x].ch[c];    //Attention
        y = x;
        
while (y) {res += T[y].mul; T[y].mul = 0; y = T[y].fail;}      //Attention
    }
}
int main()
{
    
int tests, n;
    scanf(
"%d"&tests);
    re(testno, tests) {
        N 
= 1; T[root].mul = 0; re(i, SZ) T[root].ch[i] = 0;
        scanf(
"%d"&n); getchar();
        re(i, n) {
            gets(tmp0);
            s0 
= tmp0;
            ins();
        }
        gets(tmp);
        A 
= tmp;
        mkf();
        solve();
        printf(
"%d\n", res);
    }
    
return 0;
}

?011q?0?9日】今天发C匚wq程中的一个可优化的地方:(x)对于一个点x以及(qing)它的所有返回结点(q里把所有沿着x的失败指针不断上溯直到root路径上的l点都称回结点)Q由于不可重复计敎ͼ可以它们的mul值置为原来mul值的相反敎ͼ-mulQ,而不?Q表Cl点已经l计q。这样在下一ơy的上溯过E中一旦发C个mulgؓ(f)负的点就不用l箋上溯了,因ؓ(f)上面的点一定也已经l计q了?br />当然Q这仅限于单MQ如果是多主串则需要在每次匚w之前把Trie?wi)中所有结点的mul|如果是负数的的话Q全部重新取反。ؓ(f)了节省时_(d)可以在匹配过E中把所有统计过的(mul值改数的Q结点全部放q一个辅助的队列里,然后取反时只要处理队列中的结点就行了?br />
加入该优化后的代码(solve部分Q:(x)
void solve()
{
    
int len = A.length(), x = root, y, c; res = 0;
    re(i, len) {
        c 
= A[i] - 97;
        
while (x && !T[x].ch[c]) x = T[x].fail;
        
if (!x) x = root; else x = T[x].ch[c];
        y 
= x;
        
while (y && T[y].mul >= 0) {res += T[y].mul; T[y].mul = -T[y].mul; y = T[y].fail;}
    }
}

下面是优化的实测l果Q第一个ؓ(f)优化后的Q第二个Z化前的)Q可以看出,该优化的力度很大?img height="48" alt="" src="http://www.shnenglu.com/images/cppblog_com/matono1/评l果/ACauto.gif" width="564" border="0" longdesc="" />


Mato_No1 2011-10-19 19:47 发表评论
]]>
环Ş串的最优断炚w?/title><link>http://www.shnenglu.com/MatoNo1/archive/2011/04/23/144852.html</link><dc:creator>Mato_No1</dc:creator><author>Mato_No1</author><pubDate>Sat, 23 Apr 2011 08:09:00 GMT</pubDate><guid>http://www.shnenglu.com/MatoNo1/archive/2011/04/23/144852.html</guid><wfw:comment>http://www.shnenglu.com/MatoNo1/comments/144852.html</wfw:comment><comments>http://www.shnenglu.com/MatoNo1/archive/2011/04/23/144852.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/MatoNo1/comments/commentRss/144852.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/MatoNo1/services/trackbacks/144852.html</trackback:ping><description><![CDATA[【问题描q?br>l出一个环形的字符串SQ长度ؓ(f)NQ现在要扑ֈ一个断开点,使得从这里断开后的字符串字典序最。或者说Q对于长度ؓ(f)N的字W串S[0..N-1]Q找C个位|iQ得字W串S' = S[i..N-1] + S[0..i-1]的字典序最。若存在多个q样的最优断点,则取最左边(i最?的那个?br>【Sample Input?br>amandamanda<br>【Sample Output?br>10<br>Q从W?0位断开后得到的字符?aamandamand"的字典序?1个断开位置中最的Q?br><br>【分析?br>首先这个环形串拆开Q只需S[0..N-1]的后面再接上S[0..N-2]卛_Q如对于样例Q可构造字W串T = "amandamandaamandamand"Q,则T的Q意一个长度ؓ(f)N的子串T[i..i-N+1]是S从第i位断开得到的字W串。此旉题就变成了:(x)<span style="COLOR: red"><strong>l出一个长度ؓ(f)(2N-1)的字W串Q求出其所有长度ؓ(f)N的子串中字典序最的</strong></span>?br><br>设F[x]?span style="COLOR: red"><strong>T中所有v始位于N的长度ؓ(f)x的子串中字典序最的子串的v始位Q若有多个则取最左边的)</strong></span>Q如对于T="abaabaaababaabaaa"Q有F[0]=F[1]=0QF[2]=2QF[3]=F[4]=5……本题的目的就是求出F[N]的倹{一开始已知的只有F[0]=0Q长度ؓ(f)0的字W串都是IZQ字典序都是最的Q取最左边的第0位)?br><br>可以发现QF数组有很多重要的性质Q?br><span style="COLOR: #ff0000"><strong>性质1 F[0..N]数组是单调递增的?/strong></span><br>证明Q用反证法。设存在一个值x(0<=x<N)使得F[x]>F[x+1]则根据定义,有T[F[x+1]..F[x+1]+x]<=T[F[x]..F[x]+x]Q这里一定不?x)越界,即F[x]+x的g定不大于(2N-1)Q因为x<NQ又Ҏ(gu)得F[x]<NQ故F[x]+x<2NQ,q样Q必有T[F[x+1]..F[x+1]+x-1]<=T[F[x]..F[x]+x-1]。然而根据F[x]的定义又可以得到T[F[x+1]..F[x+1]+x-1]>T[F[x]..F[x]+x-1]Q否则F[x]的值就应该{于F[x+1]的gQ,矛盾Q故在F[0..N]中不可能存在MF[x]>F[x+1]的情况,也即F[0..N]数组是单调递增的(以下F[0..N]数组UCؓ(f)F数组Q?br><span style="COLOR: #ff0000"><strong>性质2 对于L值x(0<=x<N)Q必然满F[x+1]=F[x]或F[x+1]>F[x]+x?/strong></span><br>证明Q因为前面已l证明了F数组是单调递增的,q里只需证明对于Lx(0<=x<N)Q不存F[x]<F[x+1]<=F[x]+x的情况即可?br>q里同样用反证法。设存在一个值x(0<=x<N)使得F[x]<F[x+1]<=F[x]+x。则Ҏ(gu)定义有T[F[x+1]..F[x+1]+x]<T[F[x]..F[x]+x]且T[F[x]..F[x]+x-1]<=T[F[x+1]..F[x+1]+x-1]Q这样必有T[F[x]..F[x]+x-1]=T[F[x+1]..F[x+1]+x-1]且T[F[x+1]+x]<T[F[x]+x]。设D=F[x+1]-F[x]Q则T[F[x]]=T[F[x]+D]Q因为D<=xQ可得T[F[x]+D]=T[F[x]+2D]Q即T[F[x]]=T[F[x]+2D]。这PT[F[x]..F[x]+x-D-1]=T[F[x]+2D..F[x]+x+D-1]Q又因ؓ(f)T[F[x]+x-D]=T[F[x]+x]Q而T[F[x+1]+x]Q即T[F[x]+x+D]]Q?lt;T[F[x]+x]Q这PT[F[x]+x+D]<T[F[x]+x-D]Q也是QT[F[x]+2D..F[x]+x+D]<T[F[x]..F[x]+x-D]Q这样可以得出,?F[x]+2D)位开始的L长度不小?x-D)的子Ԍ其字典序都小于从F[x]位开始的同样长度的子Ԍ׃F[x]<F[x+1]<=F[x]+xQD=F[x+1]-F[x]Q所以有1<=D<=xQ这PF[x]的值就应该?F[x]+2D)了,q显然不可能。所以,一开始假讄q种情况是不可能存在的,卛_于Q意值xQ?<=x<NQ,必然满F[x+1]=F[x]或F[x+1]>F[x]+x?br><br>Ҏ(gu)F数组的以上两个性质可以设计出本题的法Q?br>讄前已l求ZF[0..x-1]的|且F[x-1]=i。首先将T[0..i-1]全部删去Q因为F数组是单调递增的,F[x]的g定不于iQ,然后对T自n作扩展KMPQ就是以T为模板串QT为子串的扩展KMPQ相当于光处理部分Q,一开始先F[x]|ؓ(f)iQ设Wj位的匚w长度为next[j]Q若next[j]=x-1且T[j+x-1]<T[i+x-1]Q则F[x]的值改为jQ这h描一遍,xZF[x]的倹{若扫描q程中未出现Mnext[j]=x-1Q则设所有next[j]g于x的最next[j]gؓ(f)yQ则可以直接得到F[x..y-1]的值均{于F[x-1]。就q样直到求出F[N]的gؓ(f)止?br><br>旉复杂度:(x)O(N<span style="FONT-FAMILY: symbol">Ö</span>N)Q可以根据性质2得到? <img src ="http://www.shnenglu.com/MatoNo1/aggbug/144852.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/MatoNo1/" target="_blank">Mato_No1</a> 2011-04-23 16:09 <a href="http://www.shnenglu.com/MatoNo1/archive/2011/04/23/144852.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>KMP和扩展KMPhttp://www.shnenglu.com/MatoNo1/archive/2011/04/17/144390.htmlMato_No1Mato_No1Sun, 17 Apr 2011 11:11:00 GMThttp://www.shnenglu.com/MatoNo1/archive/2011/04/17/144390.htmlhttp://www.shnenglu.com/MatoNo1/comments/144390.htmlhttp://www.shnenglu.com/MatoNo1/archive/2011/04/17/144390.html#Feedback1http://www.shnenglu.com/MatoNo1/comments/commentRss/144390.htmlhttp://www.shnenglu.com/MatoNo1/services/trackbacks/144390.html【算法?br />设next[i]为满B[i-z+1..i]==B[0..z-1]的最大的z|也就是B的自w匹配)。设目前next[0..lenB-1]与ex[0..i-1]均已求出Q要用它们来求ex[i]的倹{?br />Ҏ(gu)ex的定义,有A[i-1-ex[i-1]+1..i-1]==B[0..ex[i-1]-1]Q这Ӟ若有A[i]==B[ex[i-1]]Q则可以直接得到ex[i]=ex[i-1]+1Q因为i-1-ex[i-1]+1即i-ex[i-1]Q现在由于A[i]==B[ex[i-1]]Q可得A[i-ex[i-1]..i]==B[0..ex[i-1]]Q即A[i-ex[i-1]+1-1..i]==B[0..ex[i-1]+1-1]Q所以ex[i]=ex[i-1]+1Q。若A[i]!=B[ex[i-1]]Q?br />设j=next[ex[i-1]-1]Q则Ҏ(gu)next定义得B[ex[i-1]-j..ex[i-1]-1]==B[0..j-1]Q又因ؓ(f)A[i-ex[i-1]..i-1]==B[0..ex[i-1]-1]得A[i-j..i-1]==B[ex[i-1]-j..ex[i-1]-1]Q这hA[i-j..i-1]==B[0..j-1]Q也是此时只需再比较A[i]与B[j]的值是否相{即可,若相{,可得ex[i]=j+1Q若仍不相等Q则更新j为next[j-1]Ql比较A[i]与B[j]是否相等……直到A[i]与B[j]相等或直到j==0ӞA[i]仍不{于B[j]Q此时ex[i]=0。边界:(x)求ex[0]Ӟ初始jQ用来代替ex[i-1]Qؓ(f)0?br />现在q有一个问题,如何求nextQ显然next是以B自n为模板串QB为子串的“自n匚w”Q用cM的办法即可,唯一不同的是next[0]=lenB可以直接得到Q求next[1]Ӟ初始jQ代替next[i-1]Qؓ(f)0?br />【核心代码?br />
    lenA = strlen(A); lenB = strlen(B);
    next[
0= lenB;
    
int j = 0;
    re2(i, 
1, lenB) {
        
while (j && B[i] != B[j]) j = next[j - 1];
        
if (B[i] == B[j]) j++;
        next[i] 
= j;
    }
    j 
= 0;
    re(i, lenA) {
        
while (j && A[i] != B[j]) j = next[j - 1];
        
if (A[i] == B[j]) j++;
        ex[i] 
= j;
    }
扩展KMPQ给出模板串A和子串BQ长度分别ؓ(f)lenA和lenBQ要求在U性时间内Q对于每个A[i]Q?<=i<lenA)Q求出A[i..lenA-1]与B的最长公共前~长度Q记为ex[i]Q或者说Qex[i]为满A[i..i+z-1]==B[0..z-1]的最大的z|。扩展KMP可以用来解决很多字符串问题,如求一个字W串的最长回文子串和最镉K复子丌Ӏ?br />【算法?br />设next[i]为满B[i..i+z-1]==B[0..z-1]的最大的z|也就是B的自w匹配)。设目前next[0..lenB-1]与ex[0..i-1]均已求出Q要用它们来求ex[i]的倹{?br />设p为目前A串中匚w到的最q位|,k其匹配到最q位|的|或者说Qk是在0<=i0<i的所有i0gQi0+ex[i0]-1的值最大的一个,p个最大|即k+ex[k]-1Q,昄Qp之后的所有位都是未知的,也就是目前还无法知道A[p+1..lenA-1]中的M一位和B的Q何一位是否相{?br />Ҏ(gu)ex的定义可得,A[k..p]==B[0..p-k]Q因为i>kQ所以又有A[i..p]==B[i-k..p-k]Q设L=next[i-k]Q则Ҏ(gu)next的定义有B[0..L-1]==B[i-k..i-k+L-1]。考虑i-k+L-1与p-k的关p:(x)
Q?Qi-k+L-1<p-kQ即i+L<=p。这Ӟ由A[i..p]==B[i-k..p-k]可以得到A[i..i+L-1]==B[i-k..i-k+L-1]Q又因ؓ(f)B[0..L-1]==B[i-k..i-k+L-1]所以A[i..i+L-1]==B[0..L-1]Q这p明ex[i]>=L。又׃next的定义可得,A[i+L]必然不等于B[L]Q否则A[i..i+L]==B[0..L]Q因为i+L<=pQ所以A[i..i+L]==B[i-k..i-k+L]Q这样B[0..L]==B[i-k..i-k+L]Q故next[i-k]的值应为L+1或更大)Q这P可以直接得到ex[i]=LQ?/strong>
Q?Qi+k-L+1>=p-kQ即i+L>p。这Ӟ首先可以知道A[i..p]和B[0..p-i]是相{的Q因为A[i..p]==B[i-k..p-k]Q而i+k-L+1>=p-kQ由B[0..L-1]==B[i-k..i-k+L-1]可得B[0..p-i]==B[i-k..p-k]Q即A[i..p]==B[0..p-i]Q,然后Q对于A[p+1]和B[p-i+1]是否相等Q目前是不知道的Q因为前面已l说q,p是目前A串中匚w到的最q位|,在p之后无法知道M一位的匚w信息Q,因此Q要从A[p+1]与B[p-i+1]开始往后l匹配(设j为目前B的匹配位|的下标Q一开始j=p-i+1Q每ơ比较A[i+j]与B[j]是否相等Q直C相等或者越界ؓ(f)止,此时的j值就是ex[i]的|。在q种情况下,p的值必然会(x)得到延Q因此更新k和p的倹{?br />边界Qex[0]的值需要预先求出,然后初始的k设ؓ(f)0Qp设ؓ(f)ex[0]-1?br />对于求next数组Q也?#8220;自n匚w”Q类似KMP的方法处理即可。唯一的不同点也在边界上:(x)可以直接知道next[0]=lenBQnext[1]的值预先求出,然后初始k=1Qp=ex[1]?br />
需要严重注意的是,在上q的情况Q?Q中Q本该从A[p+1]与B[p-i+1]开始匹配,但是Q若p+1<iQ也是p-i+1<0Q这U情冉|有可能发生的Q当ex[i-1]=0Q且前面的ex值都没有延到i?qing)以后的时候)的话Q需要将A、B的下标都?Q因为此时p必然{于i-2Q如果A、B的下标用两个变量x、y控制的话Qx和y都要?Q!Q?/span>

【核心代码?br />
lenA = strlen(A); lenB = strlen(B);
    next[
0= lenB; next[1= lenB - 1;
    re(i, lenB
-1if (B[i] != B[i + 1]) {next[1= i; break;}
    
int j, k = 1, p, L;
    re2(i, 
2, lenB) {
        p 
= k + next[k] - 1; L = next[i - k];
        
if (i + L <= p) next[i] = L; else {
            j 
= p - i + 1;
            
if (j < 0) j = 0;
            
while (i + j < lenB && B[i + j] == B[j]) j++;
            next[i] 
= j; k = i;
        }
    }
    
int minlen = lenA <= lenB ? lenA : lenB; ex[0= minlen;
    re(i, minlen) 
if (A[i] != B[i]) {ex[0= i; break;}
    k 
= 0;
    re2(i, 
1, lenA) {
        p 
= k + ex[k] - 1; L = next[i - k];
        
if (i + L <= p) ex[i] = L; else {
            j 
= p - i + 1;
            
if (j < 0) j = 0;
            
while (i + j < lenA && j < lenB && A[i + j] == B[j]) j++;
            ex[i] 
= j; k = i;
        }
    }
【时间复杂度分析?br />在KMP和扩展KMP中,不管是A串还是BԌ其匹配位|都是单调递增的,故L间复杂度是线性的Q都为O(lenA + lenB)Q只是扩展KMP比KMP的常数更大一些)?br />【应用?br />KMP和扩展KMP在解军_W串问题中有大用。很多看上去很猥琐的字符串问题,都可以归l到q两U算法之中。另外,q里?#8220;字符?#8221;可以延Z切类型的数组Q而不仅仅是字W数l?img src ="http://www.shnenglu.com/MatoNo1/aggbug/144390.html" width = "1" height = "1" />

Mato_No1 2011-04-17 19:11 发表评论
]]>
91ɫۺϾþ| þþùƷվ| þþƷѹۿ97| þ99Ʒþþ| Ʒþþþù| þۺϾɫۺվ| þۺ༤| ŷ츾XXXXԾþþ| ˾þþƷӰԺ| ɫۺϾþҹɫƷ| ޹Ʒ۲ӰԺþ| ɫþþþSWAGƷ| þøԴƷ999| Ʒþþþþþþ| Ժձһձþ| 91Ʒ91Ⱦþþþø | re99þþƷ99| þҹɫƷվ| 99þþƷһ| þۺϾþۺϾþ| þó18վ| þӰӹ| þֻоƷ߹ۿ| þþƷа| þþƷƷëƬ| þ99Ʒþ| ձɫվWWWþ| þëƬһ| 777ҹƷþav| þþƷ99þ㽶| þ| ľþþþ| ƷVAþþþþþñ| þwww˳ɾƷ㽶| ھƷþþӰԺ | Ʒһþù| 99þþƷѿ| ŷ˾þþƷ| ɫۺϾþۺ| þþþAVרJN| þó鱬Ļ|