POJ 3167 Cow Patterns
2016-09-26 13:09
309 查看
题目链接:http://poj.org/problem?id=3167
5
6
2
10
10
7
3
2
9
1
4
4
3
2
1
3
[翻译来自BZOJ 1729]
先把文本串取名为a串,模式串叫b串。以下所说的”相等”若无特殊说明即为题意所说的相等
定义一个函数getval(ch,str,l,r),返回的值为ch在str[l~r]中的真实值,即将str[l~r]中的值排序离散化后ch的值。则题意即为:在a串中找出一段长为m的区间[l,r],使对任意的1≤i≤m,getval(a[l+i-1],a,l,r)均等于getval(b[i],b,1,m)
可以发现这样一个特性:
当a串即将匹配到i,b串已经匹配到j时,即两端蓝色相等时,只要getval(a[i],a,l,r)=getval(b[j+1],b,1,j+1),两段蓝色+黄色也相等
可以,这貌似跟普通的字符串匹配长得一模一样,这很kmp。有了这个特性,只要能快速求出getval()的值,就成了一个普通的kmp了。
getval的值,其实是返回某个数(数跟字符其实是一样的)在某堆数中的排名。是什么决定了一个数x的排名?是小于x的数的个数,等于x的数的个数。如果这两个个数与另一个y的两个个数都相等,那么x跟y在各自字符串的各自区间内的getval值就相等了
那么就可以O(n*s)求出某个字符ch在1~i的出现次数,用前缀和的方式求出来,然后就能O(1)求出某个区间某个字符出现次数。至于小于某个字符的出现次数,当场大力O(s)求一下就好啦
总时间复杂度O(n*s)
Description
约翰的N(1≤N≤100000)只奶牛中出现了K(1≤K≤25000)只爱惹麻烦的坏蛋。奶牛们按一定的顺序排队的时候,这些坏蛋总会站在一起。为了找出这些坏蛋,约翰让他的奶牛排好队进入牛棚,同时需要你的慧眼来识别坏蛋,为了区分,约翰给所有奶牛都发了号牌,上面写着一个1~S(1≤S≤25)之间的数字。虽然这不是一个完美的方法,但也能起一点作用。现在,约翰已经不记得坏蛋们的具体号码。但是凭他的记忆,他给出一个“模式串”。原坏蛋的号码如果相同,模式串中他们的号码依然相同。模式串中坏蛋们之间号码的大小关系也与原号码相同的。比如,对于这样一个模式串:1,4,4,3,2,1。原来的6只坏蛋,排最前面的与排最后的号码相同(尽管不一定是1),而且他们的号码在团伙中是最小的。第2,3位置的坏蛋,他们的号码也相同(不一定是4),且是坏蛋团伙中最大的。现在所有奶牛排成队列,号码依次是这样:5,6,2,10,10,7,3,2,9存在子串2,10,10,7,3,2,满足模式串的相同关系和大小关系,所以这就是坏蛋团伙,请找出K个坏蛋的困伙的所有可能性。Input
第1行输入三个整数N,K,S。接下来N行每行输入一只牛的号码。接下来K行每行输入一个模式串的号码。Output
第1行输出一个整数B。接下来B行,每行一个整数,表示一种可能下的坏蛋团伙的起始位置。Sample Input
9 6 105
6
2
10
10
7
3
2
9
1
4
4
3
2
1
Sample Output
13
[翻译来自BZOJ 1729]
Solution
这道题如果没有那种奇怪的匹配方式的话,就是一道很果的kmp。但这题的匹配方式怎么看怎么恶心先把文本串取名为a串,模式串叫b串。以下所说的”相等”若无特殊说明即为题意所说的相等
定义一个函数getval(ch,str,l,r),返回的值为ch在str[l~r]中的真实值,即将str[l~r]中的值排序离散化后ch的值。则题意即为:在a串中找出一段长为m的区间[l,r],使对任意的1≤i≤m,getval(a[l+i-1],a,l,r)均等于getval(b[i],b,1,m)
可以发现这样一个特性:
当a串即将匹配到i,b串已经匹配到j时,即两端蓝色相等时,只要getval(a[i],a,l,r)=getval(b[j+1],b,1,j+1),两段蓝色+黄色也相等
可以,这貌似跟普通的字符串匹配长得一模一样,这很kmp。有了这个特性,只要能快速求出getval()的值,就成了一个普通的kmp了。
getval的值,其实是返回某个数(数跟字符其实是一样的)在某堆数中的排名。是什么决定了一个数x的排名?是小于x的数的个数,等于x的数的个数。如果这两个个数与另一个y的两个个数都相等,那么x跟y在各自字符串的各自区间内的getval值就相等了
那么就可以O(n*s)求出某个字符ch在1~i的出现次数,用前缀和的方式求出来,然后就能O(1)求出某个区间某个字符出现次数。至于小于某个字符的出现次数,当场大力O(s)求一下就好啦
总时间复杂度O(n*s)
Code
#include <cstdio> #include <cctype> #include <algorithm> using namespace std; #define N 100010 #define S 26 #define mid ((l+r)>>1) #define foru(i,l,r) for (int i=l; i<=r; i++) #define read(x) (x=getint()) int a ,b ,n,m,k,p ,srt ,suma[S] ,sumb[S] ,an,ans ; int getint() { int x,f=1; char ch; while (!isdigit(ch=getchar())) f=ch=='-'?-1:1; x=ch-'0'; while (isdigit(ch=getchar())) x=x*10+ch-'0'; return f*x; } void init() { read(n), read(m), read(k); foru(i,1,n) read(a[i]); foru(i,1,m) read(b[i]); foru(i,1,n) foru(j,1,k) suma[j][i]+=suma[j][i-1]+(j==a[i]); foru(i,1,m) foru(j,1,k) sumb[j][i]+=sumb[j][i-1]+(j==b[i]); } int geta(int ch, int l, int r) { int ans=0; foru(i,1,ch-1) ans+=suma[i][r]-suma[i][l-1]; return ans; } int getb(int ch, int l, int r) { int ans=0; foru(i,1,ch-1) ans+=sumb[i][r]-sumb[i][l-1]; return ans; } bool cmpab(int x, int y) { if (getb(b[x],1,x)!=geta(a[y],y-x+1,y)) return false; return sumb[b[x]][x]==suma[a[y]][y]-suma[a[y]][y-x]; } bool cmpbb(int x, int y) { if (getb(b[x],1,x)!=getb(b[y],y-x+1,y)) return false; return sumb[b[x]][x]==sumb[b[y]][y]-sumb[b[y]][y-x]; } void init_kmp(int s[], int n) { p[1]=0; int j=0; foru(i,2,n) { while (j&&!cmpbb(j+1, 4000 i)) j=p[j]; if (cmpbb(j+1,i)) j++; p[i]=j; } } void kmp() { int j=0; foru(i,1,n) { while (j&&!cmpab(j+1,i)) j=p[j]; if (cmpab(j+1,i)) j++; if (j==m) { ans[++an]=i-j+1; j=p[j]; } } } int main() { // freopen("data.txt","r",stdin); init(); init_kmp(b,m); kmp(); printf("%d\n",an); foru(i,1,an) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- POJ 3167 Cow Patterns
- POJ 3167 Cow Patterns
- POJ 3167 Cow Patterns
- POJ_3167 Cow Patterns
- 【POJ 3167】Cow Patterns (KMP+树状数组)
- poj 3167 Cow Patterns (kmp + 线段树/树状数组)
- POJ 3167 Cow Patterns 笔记
- POJ 3167 Cow Patterns (KMP+前缀和)
- POJ-3167- Cow Patterns(KMP)
- POJ 3167 Cow Patterns
- POJ 3167 Cow Patterns(模式串浮动匹配)
- POJ 3167 Cow Patterns (KMP + 树状数组)
- poj 3167 Cow Patterns(kmp)
- [poj][3167][Cow Patterns]
- POJ 3167
- pku 3167 Cow Patterns(kmp)
- poj 3167 构造比较函数的kmp
- POJ 3167 Layout(差分约束)
- HDU 4749 && POJ 3167 KMP
- POJ3167 Cow Patterns ——有趣的KMP算法——Pku3167