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\n",s);
82     for(i=0;i<s;i++)
83         printf("%d ",ans[i]);
84     printf("\n");
85     return 0;
86 }

 

posted @ 2019-07-08 23:04  lyyi2003  阅读(196)  评论(0编辑  收藏  举报