• BZOJ1729: [Usaco2005 dec]Cow Patterns 牛的模式匹配


    n<=1e5个数字,给m<=25000个数字做模板串,给的数字都<=25,求n个数中有多少个子串满足这样的与模板串匹配:长度与模板串相同,且子串中第一、二、三、……个数字在该子串中的排名和模板串中第一、二、三、……个数字在模板串中的排名相同,如:1 4 4 2和4 6 6 5匹配。

    两串匹配--KMP。但这个题的匹配模式不同于传统的匹配模式。有点难的题,但有助于更好的理解KMP的原理。

    回顾下KMP整个过程:模板串做失配函数,然后模板串中开个指针利用失配函数和原串匹配。也就是,如果我们知道“匹配”应满足什么条件,就可以完成所有的工作。

    两串匹配,满足条件:一:这两串的上一串,即当前考虑的字符去掉,本来就已经匹配了;二:当前考虑的字符加入后仍满足匹配。也就是说,只要能找到一个满足条件二的计算方式就可以做了。在此题中,这个条件二可表示为:两串分别新加进来这个数字的排名相等,而数字很小,这个排名可以迅速计算。

    错误!条件考虑不周。原来两串:1 2 3 5和2 3 4 5,现在串一加数字4,串二加数字5,排名相同,但是不能匹配的。究其原因,这里的“排名”不仅指小排名,而且指大排名,就是比他小的、比他大的数量都一样。但实际上不必这样,因为总数-小排名-大排名=这个数字出现次数,总数肯定是一样的,所以只要小排名和这个数字出现次数一样即可。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<stdlib.h>
     5 //#include<math.h>
     6 //#include<iostream>
     7 using namespace std;
     8  
     9 int n,m,T;
    10 #define maxn 100011
    11 int a[maxn],sa[maxn][30],b[maxn],sb[maxn][30],fail[maxn];
    12 bool equal(int* s1,int sa[][30],int x,int* s2,int sb[][30],int y)
    13 {
    14     int x1=0,x2=0,y1=0,y2=0;
    15     for (int i=0;i<s1[x];i++) x1+=sa[x][i]-sa[x-y][i];
    16     for (int i=0;i<s2[y];i++) y1+=sb[y][i];
    17     x2=sa[x][s1[x]]-sa[x-y][s1[x]],y2=sb[y][s2[y]];
    18     return (x1==y1 && x2==y2);
    19 }
    20 void makef()
    21 {
    22     fail[1]=fail[2]=1;
    23     for (int i=2;i<=m;i++)
    24     {
    25         int j=fail[i];
    26         while (j>1 && !equal(b,sb,i,b,sb,j)) j=fail[j];
    27         fail[i+1]=equal(b,sb,i,b,sb,j)?j+1:1;
    28     }
    29 }
    30 int ans[maxn],lans=0;
    31 int main()
    32 {
    33     scanf("%d%d%d",&n,&m,&T);
    34     memset(sa[0],0,sizeof(sa[0]));
    35     for (int i=1;i<=n;i++)
    36     {
    37         scanf("%d",&a[i]);
    38         for (int j=0;j<26;j++) sa[i][j]=sa[i-1][j];
    39         sa[i][a[i]]++;
    40     }
    41     memset(sb[0],0,sizeof(sb[0]));
    42     for (int i=1;i<=m;i++)
    43     {
    44         scanf("%d",&b[i]);
    45         for (int j=0;j<26;j++) sb[i][j]=sb[i-1][j];
    46         sb[i][b[i]]++;
    47     }
    48     makef();
    49     int j=1;
    50     for (int i=1;i<=n;i++)
    51     {
    52         while (j>1 && !equal(a,sa,i,b,sb,j)) j=fail[j];
    53         if (equal(a,sa,i,b,sb,j)) j++;
    54         if (j>m)
    55         {
    56             ans[++lans]=i-m+1;
    57             j=fail[j];
    58         }
    59     }
    60     printf("%d
    ",lans);
    61     for (int i=1;i<=lans;i++) printf("%d
    ",ans[i]);
    62     return 0;
    63 }
    View Code
  • 相关阅读:
    Ubuntu编译gdb-ARM调试环境
    12小时制字符串转24小时制字符串
    Qt QByteArray或者Char转十六进制 QString
    STM32 串口通信使用奇偶校验
    127.*.*.* 为本地回环地址,均返回127.0.0.1
    winform解析json
    qString转char*
    下载vc++运行库
    CentOS 7 通过 yum 安装 nodejs 和 npm
    go语言 工程目录
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7623410.html
Copyright © 2020-2023  润新知