• LOJ2507 CEOI2011 Matching


    题目链接

    参考了 神仙yyb的博客

    现在发现kmp不仅能匹配字符串,还可以用于处理任意模式匹配中的状态,如这题中已经匹配的序列中的数的大小关系就是一种状态,使用kmp找到模式序列的每一个前缀的border,即一个最长的前缀和后缀使得它们的数字大小关系相同,即匹配状态相同,然后在失配时跳转到一个前缀的状态继续匹配,就可以解决这个问题啦!

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 1000007
     4 int sum[N],n,m;
     5 void modify(int x,int d)
     6 {
     7     for(;x<=m;x+=x&-x)
     8         sum[x]+=d;
     9 }
    10 int query(int x)
    11 {
    12     int ans=0;
    13     for(;x;x-=x&-x)
    14         ans+=sum[x];
    15     return ans;
    16 }
    17 int read()
    18 {
    19     char c;
    20     int x;
    21     while((c=getchar())<48||c>57);
    22     x=c-48;
    23     while((c=getchar())>=48&&c<=57)
    24         x=x*10+c-48;
    25     return x;
    26 }
    27 int rk[N],nxt[N],a[N],b[N],p[N];
    28 vector<int> ans;
    29 int main()
    30 {
    31     int i;
    32     scanf("%d%d",&n,&m);
    33     for(i=1;i<=n;i++)
    34         p[read()]=i;
    35     for(i=1;i<=n;i++)
    36     {
    37         modify(p[i],1);
    38         rk[i]=query(p[i]);
    39     }
    40     memset(sum,0,sizeof(sum));
    41     nxt[1]=0;
    42     int last=2;
    43     for(i=2;i<=n;i++)
    44     {
    45         int len=nxt[i-1];
    46         while(len&&query(p[i])+1!=rk[len+1])
    47         {
    48             len=nxt[len];
    49             while(last<i-len)modify(p[last++],-1);
    50         }
    51         if(query(p[i])+1==rk[len+1])
    52         {
    53             nxt[i]=len+1;
    54             modify(p[i],1);
    55         }
    56         else nxt[i]=0;
    57     }
    58     for(i=1;i<=m;i++)
    59         a[i]=b[i]=read();
    60     sort(b+1,b+m+1);
    61     for(i=1;i<=m;i++)a[i]=lower_bound(b+1,b+m+1,a[i])-b;
    62     memset(sum,0,sizeof(sum));
    63     int len=0;
    64     last=1;
    65     for(i=1;i<=m;i++)
    66     {
    67         while(len&&query(a[i])+1!=rk[len+1])
    68         {
    69             len=nxt[len];
    70             while(last<i-len)modify(a[last++],-1);
    71         }
    72         if(query(a[i])+1==rk[len+1])
    73         {
    74             len++;
    75             modify(a[i],1);
    76             if(len==n)ans.push_back(i-len+1);
    77         }
    78         else len=0;
    79     }
    80     int s=ans.size();
    81     printf("%d
    ",s);
    82     for(i=0;i<s;i++)
    83         printf("%d ",ans[i]);
    84     printf("
    ");
    85     return 0;
    86 }
  • 相关阅读:
    剑指offer 整数中1出现的次数(从1到n整数中1出现的次数)
    剑指offer 把数组排成最小的数
    剑指offer 丑数
    剑指offer 字符串的排列
    剑指offer 数组中出现次数超过一半的数字
    剑指offer 最小的K个数
    操作系统 页面置换算法(C++实现)
    剑指offer 二叉搜索树与双向链表
    剑指offer 复杂链表的复制
    操作系统 银行家算法(C++实现)
  • 原文地址:https://www.cnblogs.com/lishuyu2003/p/11154652.html
Copyright © 2020-2023  润新知