Matching「CEOI2011」

题意

对于整数序列 \((a_1,a_2,\cdots,a_n)\)\(1\sim n\)的排列\((p_1,p_2,\cdots,p_n)\),称 \((a_1,a_2,\cdots,a_n)\)符合 \((p_1,p_2,\cdots,p_n)\),当且仅当:

  • \(\{a\}\)中任意两个数字互不相同;
  • \((a_1,a_2,\cdots,a_n)\)从小到大排序后,将会得到 \((a_{p_1},a_{p_2},\cdots,a_{p_n})\)

现在给出 \(1\sim n\) 的排列 \(\{p\}\) 和序列 \(h_1,h_2,\cdots,h_m\),请你求出哪些 \(\{h\}\) 的子串符合排列\(\{p\}\)


思路

可以想到,两个数组排列顺序一致,意味着对于每一个数,它前面比它小的数数量相等。

于是我们可以预处理出这个“顺序对”数组,然后kmp转移。

由于每一次跳区间的时候都会删一些数加一些数,所以使用树状数组进行动态维护。

代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {

	template<typename T>inline void read (T &x) {
		x=0;T f=1;char c=getchar();
		for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
		for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
		x*=f;
	}

	template<typename T>inline void write (T x) {
		if (x<0) putchar('-'),x*=-1;
		if (x>=10) write(x/10);
		putchar(x%10+'0');
	}

}

using namespace StandardIO;

namespace Project {
	
	const int N=1000100;
	
	int n,m;
	int p[N],rnk[N],h[N],b[N],v[N];
	int nxt[N];
	int tot,ans[N];
	int tree[N];
	
	#define lowbit(x) x&(-x)
	inline void update (int x,int v) {
		for (register int i=x; i<=m; i+=lowbit(i)) tree[i]+=v;
	}
	inline int query (int x) {
		int res=0;
		for (register int i=x; i; i-=lowbit(i)) res+=tree[i];
		return res;
	}
	
	inline void MAIN () {
		read(n),read(m);
		for (register int i=1; i<=n; ++i) {
			read(p[i]),rnk[p[i]]=i;
		}
		for (register int i=1; i<=m; ++i) {
			read(h[i]),b[i]=h[i];
		}
		sort(b+1,b+m+1);
		for (register int i=1; i<=m; ++i) 
			h[i]=lower_bound(b+1,b+m+1,h[i])-b;
		for (register int i=1; i<=n; ++i) v[i]=query(rnk[i]),update(rnk[i],1);
		
		
		memset(tree,0,sizeof(tree));
		for (register int i=2,j=0; i<=n; ++i) {
			while (j>0&&query(rnk[i])!=v[j+1]) {
				for (register int k=i-j; k<i-nxt[j]; ++k) 
					update(rnk[k],-1);
				j=nxt[j];
			}
			if (query(rnk[i])==v[j+1]) ++j;
			nxt[i]=j;
			update(rnk[i],1);
		}
		
		
		
		
		memset(tree,0,sizeof(tree));
		for (register int i=1,j=0; i<=m; ++i) {
			while (j==n||(j>0&&query(h[i])!=v[j+1])) {
				for (register int k=i-j; k<i-nxt[j]; ++k) 
					update(h[k],-1);
				j=nxt[j];
			} 
			if (query(h[i])==v[j+1]) ++j;
			update(h[i],1);
			if (j==n) ans[++tot]=i-n+1;
		}
		
		
		
		
		write(tot),puts("");
		for (register int i=1; i<=tot; ++i) {
			write(ans[i]),putchar(' ');
		}
	}
	
}

int main () {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	Project::MAIN();
}
posted @ 2019-11-03 11:12  Ilverene  阅读(127)  评论(0编辑  收藏  举报