1. 程式人生 > >CodeForces 432D Prefixes and Suffixes:KMP + dp

CodeForces 432D Prefixes and Suffixes:KMP + dp

它的 每次 sca prefix 多少 mil n-1 pty 出現次數

題目鏈接:http://codeforces.com/problemset/problem/432/D

題意:

  給你一個字符串s,讓你找出所有既是前綴又是後綴的子串,並輸出它們分別出現了多少次。

題解:

  先對原串求一次nex數組。

  然後枚舉位置i:

    sub(k)表示前綴s[0 to k]

    dp[i]表示sub(i)在原串s中的出現次數

    假設nex[i] = a, nex[a] = b, nex[b] = c ... nex[z] = -1

    則sub(a), sub(b), sub(c)...sub(z)均以s[i]結尾,dp[a...z]均+1。

  然而一個一個加會T...

  

  所以:

    初始時所有的 dp = 1

    每次:if(nex[i] != -1) dp[nex[i]] += dp[i]

    一路傳遞下去就好。

  

  最後從nex[len-1]開始往前跳nex。

  對於每次跳到的nex,sub(nex)一定也是s的後綴。

  此時輸出它的出現次數dp[nex]。

  另外因為要順著輸出,而nex是倒著跳的,所以先存到stack裏再輸出。

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3
#include <string.h> 4 #include <stack> 5 #define MAX_N 100005 6 7 using namespace std; 8 9 int n; 10 int dp[MAX_N]; 11 int nex[MAX_N]; 12 char s[MAX_N]; 13 14 void cal_nex(char *p,int len) 15 { 16 nex[0]=-1; 17 int k=-1; 18 for(int i=1;i<len;i++) 19 {
20 while(k>-1 && p[i]!=p[k+1]) k=nex[k]; 21 if(p[i]==p[k+1]) k++; 22 nex[i]=k; 23 } 24 } 25 26 int main() 27 { 28 scanf("%s",s); 29 n=strlen(s); 30 cal_nex(s,n); 31 for(int i=0;i<n;i++) dp[i]=1; 32 for(int i=n-1;i>=0;i--) 33 { 34 if(nex[i]!=-1) dp[nex[i]]+=dp[i]; 35 } 36 stack<int> stk; 37 int p=n-1; 38 while(p!=-1) 39 { 40 stk.push(p); 41 p=nex[p]; 42 } 43 cout<<stk.size()<<endl; 44 while(!stk.empty()) 45 { 46 int now=stk.top(); 47 stk.pop(); 48 cout<<now+1<<" "<<dp[now]<<endl; 49 } 50 }

CodeForces 432D Prefixes and Suffixes:KMP + dp