2119: 股市的预测

8 篇文章 0 订阅

题意:

问差分后相隔为b的相同子串对数

题解:

好题啊
首先枚举子串的长度L
有一个不错的思路是每隔L放一个障碍点,对于每个点统计穿过这个点的答案个数,能做到不重不漏
在这里插入图片描述
对于关键点i,设 l = i , r = i + B + L l=i,r=i+B+L l=i,r=i+B+L
求出 ( 1 , l ) , ( 1 , r ) (1,l),(1,r) (1,l),(1,r)的lcs和 ( l , n ) , ( r , n ) (l,n),(r,n) (l,n),(r,n)的lcp即可得出答案
code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
#define LLu unsigned long long
using namespace std;
const LLu base=2333;
int n,B,A[50010],a[50010];
LL ans=0;
LLu pre[50010],c[50010];
LLu Hash(int l,int r) {return c[r]-c[l-1]*pre[r-l+1];}
bool check(int l1,int r1,int l2,int r2)
{
    if(l1<1||l2<1||r1>n||r2>n) return false;
    return Hash(l1,r1)==Hash(l2,r2);
}
int lcs(int l,int r)
{
    int ans,L=1,R=n;
    while(L<=R)
    {
        int mid=(L+R)/2;
        if(check(l,l+mid-1,r,r+mid-1)) ans=mid,L=mid+1;
        else R=mid-1;
    }
    return ans;
}
int lcp(int l,int r)
{
    int ans,L=1,R=n;
    while(L<=R)
    {
        int mid=(L+R)/2;
        if(check(l-mid+1,l,r-mid+1,r)) ans=mid,L=mid+1;
        else R=mid-1;
    }
    return ans;
}
int main()
{
    scanf("%d %d",&n,&B);
    pre[0]=1;for(int i=1;i<=50000;i++) pre[i]=pre[i-1]*base;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i-1]=a[i]-a[i-1];n--;
    for(int i=1;i<=n;i++) c[i]=c[i-1]*base+a[i];
    //for(int i=1;i<=n;i++) printf("%d ",a[i]);printf("\n");
    for(int l=1;l*2+B<=n;l++)
        for(int j=1;j+l+B<=n;j+=l)
        {
            if(a[j]==a[j+B+l])
            {
                int L=lcs(j,j+B+l),R=lcp(j,j+B+l);
                L=min(L,l);R=min(R,l);
                ans+=max(L+R-l,0);
                //printf("%d %d %d %d\n",j,j+B+l,L,R);
            }
        }
    printf("%lld",ans);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值