poj3167 Cow Patterns

78 篇文章 0 订阅

Description A particular subgroup of K (1 <= K <= 25,000) of Farmer
John’s cows likes to make trouble. When placed in a line, these
troublemakers stand together in a particular order. In order to locate
these troublemakers, FJ has lined up his N (1 <= N <= 100,000) cows.
The cows will file past FJ into the barn, staying in order. FJ needs
your help to locate suspicious blocks of K cows within this line that
might potentially be the troublemaking cows.

FJ distinguishes his cows by the number of spots 1..S on each cow’s
coat (1 <= S <= 25). While not a perfect method, it serves his
purposes. FJ does not remember the exact number of spots on each cow
in the subgroup of troublemakers. He can, however, remember which cows
in the group have the same number of spots, and which of any pair of
cows has more spots (if the spot counts differ). He describes such a
pattern with a sequence of K ranks in the range 1..S. For example,
consider this sequence:

  1 4 4 3 2 1

In this example, FJ is seeking a consecutive sequence of 6 cows from
among his N cows in a line. Cows #1 and #6 in this sequence have the
same number of spots (although this number is not necessarily 1) and
they have the smallest number of spots of cows #1..#6 (since they are
labeled as ‘1’). Cow #5 has the second-smallest number of spots,
different from all the other cows #1..#6. Cows #2 and #3 have the same
number of spots, and this number is the largest of all cows #1..#6.

If the true count of spots for some sequence of cows is:

5 6 2 10 10 7 3 2 9

then only the subsequence 2 10 10 7 3 2 matches FJ’s pattern above.

Please help FJ locate all the length-K subsequences in his line of
cows that match his specified pattern.

Input Line 1: Three space-separated integers: N, K, and S

Lines 2..N+1: Line i+1 describes the number of spots on cow i.

Lines N+2..N+K+1: Line i+N+1 describes pattern-rank slot i.

Output Line 1: The number of indices, B, at which the pattern matches

Lines 2..B+1: An index (in the range 1..N) of the starting location
where the pattern matches.

对于两个子串,如果对于每个位置,都有【在他之前且小于他】的元素的个数相等,且【在他之前且小于等于他】的元素个数相等,那么这两个子串就是等价的。
而且注意到,如果两个子串相等,那么在他们后面再添加一个元素的时候,只需要验证新添加的元素是否符合即可,前面的元素不受影响。
于是可以借用字符串中的kmp算法进行模式匹配。
对应的,判断条件b[j+1]==a[i]就变成了
tot1[j+1]==qry(a[i]-1)&&tot2[j+1]==qry(a[i])
其中tot1(2)[k]表示串b[1..k]中小于(小于等于)b[k]的个数,可以预处理出来,qry(x)表示询问小于等于x的数的个数。
在进行i++,j++,j=next[j]的同时也要注意维护当前串中数的个数。
考虑到s<=15,直接开数组维护即可,如果s较大,可以用树状数组优化到单步操作O(logs)。

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
vector<int> ans;
int a[100010],b[25010],next[25010],sum[30],cnt[30],s,tot1[25010],tot2[25010];
int qry(int x)
{
    int ans=0;
    for (int i=1;i<=x;i++)
      ans+=sum[i];
    return ans;
}
int main()
{
    int i,j,k,m,n,p,q,x,y,z;
    scanf("%d%d%d",&n,&m,&s);
    for (i=1;i<=n;i++)
      scanf("%d",&a[i]);
    for (i=1;i<=m;i++)
      scanf("%d",&b[i]);
    for (i=1;i<=m;i++)
    {
        tot1[i]=qry(b[i]-1);
        tot2[i]=qry(b[i]);
        sum[b[i]]++;
    }
    memset(sum,0,sizeof(sum));
    for (i=2,j=0;i<=m;i++)
    {
        while (j&&(tot1[j+1]!=qry(b[i]-1)||tot2[j+1]!=qry(b[i])))
        {
            for (k=i-j;k<i-next[j];k++)
              sum[b[k]]--;
            j=next[j];
        }
        if (tot1[j+1]==qry(b[i]-1)&&tot2[j+1]==qry(b[i])) j++;
        next[i]=j;
        sum[b[i]]++;
    }
    memset(sum,0,sizeof(sum));
    for (i=1,j=0;i<=n;i++)
    {
        while (j==m||(j&&(tot1[j+1]!=qry(a[i]-1)||tot2[j+1]!=qry(a[i]))))
        {
            for (k=i-j;k<i-next[j];k++)
              sum[a[k]]--;
            j=next[j];
        }
        if (tot1[j+1]==qry(a[i]-1)&&tot2[j+1]==qry(a[i])) j++;
        if (j==m) ans.push_back(i-m+1);
        sum[a[i]]++;
    }
    printf("%d\n",ans.size());
    for (i=0;i<ans.size();i++)
      printf("%d\n",ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值