题目来源:
http://acm.hdu.edu.cn/showproblem.php?pid=4749
题意:
题意:给出两个数字串A、B。问A中有多少不相交的子串a能匹配B。匹配的意思是a中任意两个位置i和j的大小关系和B的这两个位置的大小关系是一样的。
思路:若是完全一模一样的匹配的话那么KMP是很好理解的。那么对于上述的比较方式怎么比较两个串相等呢?对于a的位置j和B的位置i(j < i),我们比较aa(1,2 ,...j) 与bb(i - j + 1 , ... , i)这两个串中,j之前aa中小于(或 等于 或 大于)a[j] 的个数, 是否 == 与 i之前bb中小于(或 等于 或大于) b[i] 的个数 。
一个个匹配过去,如果前缀匹配,并且加上当前字母后,前面比这个字母小的,相等的,大于的数字个数都相等,就是匹配 。
代码如下:
const int Max_N = 100005 ; int sumt[Max_N][26] , sump[Max_N][26] ; // sum[i][j]表示从第1位到第i位,有sum[i][j] 个j int TT[Max_N] , PP[Max_N] , next[Max_N] ; int n , m , k ; // 每次匹配时 是 // (1 ,2 ,... , j) // 与(i-j + 1 , ... , i)进行匹配 bool ok1(int i, int j){ int sma1= 0 , equ1 = 0 , sma2 = 0 , equ2 = 0 ; int h ; for(h = 1 ; h <= k ; h++){ if(h < PP[i]) sma1 += sump[i][h] - sump[i - j][h] ; else if(h == PP[i]) equ1 += sump[i][h] - sump[i - j][h] ; if(h < PP[j]) sma2 += sump[j][h] ; else if(h == PP[j]) equ2 += sump[j][h] ; } return (sma1 == sma2) && (equ1 == equ2) ; } void get_next(){ int i , k = 0 ; next[1] = 0 ; for( i = 2 ; i<= m ; i++){ while(k > 0 && !ok1(i , k + 1)) k = next[k] ; if(ok1(i, k + 1)) k ++ ; next[i] = k ; } } bool ok2(int i , int j){ int sma1 = 0 , equ1 = 0 , sma2 = 0 , equ2 = 0 ; int h ; for(h = 1 ; h <= k ; h++){ if(h < TT[i]) sma1 += sumt[i][h] - sumt[i - j][h] ; else if(h == TT[i]) equ1 += sumt[i][h] - sumt[i - j][h] ; if(h < PP[j]) sma2 += sump[j][h] ; else if(h == PP[j]) equ2 += sump[j][h] ; } return (sma1 == sma2) && (equ1 == equ2) ; } int kmp(){ int i , k = 0 ; int cnt = 0 ; for(i = 1 ; i<= n ; i++){ while(k > 0 && !ok2(i , k + 1)) k = next[k] ; if(ok2(i , k + 1)) k ++ ; if(k == m){ cnt ++ ; k = 0 ; // 特殊处理, 字串不相交 } } return cnt ; } int main(){ while(scanf("%d%d%d" , &n ,&m ,&k) != EOF){ int i , j ; memset(sumt , 0 , sizeof(sumt)) ; memset(sump , 0 , sizeof(sump)) ; for(i = 1 ; i<= n ; i++){ scanf("%d" , &TT[i]) ; for(j = 1 ; j<= k ; j++) sumt[i][j] = sumt[i - 1][j] ; sumt[i][TT[i]] ++ ; } for(i = 1 ; i<= m ; i++){ scanf("%d" , &PP[i]) ; for(j = 1 ; j <= k ; j++) sump[i][j] = sump[i - 1][j] ; sump[i][PP[i]] ++ ; } get_next() ; printf("%d\n" , kmp()) ; } return 0 ; }