1 条题解

  • 0
    @ 2026-9-24 15:54:38

    Change log

    • 2023.9.22 修改少量 LaTeX 的使用。

    博客内食用效果更佳(点我)\color{red}博客内食用效果更佳(点我)

    复杂度:O(nlog⁡n)O(n\log n)

    完整思路

    纯纯的思维好题。考虑对所求答案的转化。

    设小串为 tt,其出现的起始位置为 q+1q+1(是众多出现位置的其中一个),即使得 cq+i=ti(1≤i≤m)c_{q+i}=t_i(1\le i\le m),显然有对于 q>n−mq>n-m 是不合法的。

    我们将题意转化为求合法 qq 的数量,考虑枚举每一个 tit_i。

    当 ti=0t_i=0 时,有 0≤(a(q+i)+b) mod n<p0\le\left(a(q+i)+b\right)\ \mathrm{mod}\ n<p。
    当 ti=1t_i=1 时,有 p≤(a(q+i)+b) mod n<np\le\left(a(q+i)+b\right)\ \mathrm{mod}\ n<n。

    接下来以 ti=0t_i=0 为例,有 0≤(aq+ai+b) mod n<p0\le\left(aq+ai+b\right)\ \mathrm{mod}\ n<p,其中 ai+bai+b 可以看做常数,对于此不等式组可以解出 aqaq 的范围,是连续的一或两个区间(因为 mod n\mathrm{mod}\ n 后求出的区间可看做环上一段区间,可能是 [0,x],[y,n−1][0,x],[y,n-1] 的形式)。

    于是我们得到了 mm 个不等式限制 aqaq 的范围(在 mod n\mathrm{mod}\ n 意义下),题目中给出了 a⊥na\perp n 的条件,所以一个 aqaq 也只对应一个 qq。所以我们求所有满足不等式限制的 aqaq 个数减去不合法 qq 的个数即可。

    考虑到值域很大,所以把每个 l,rl,r 离散化,差分地对于每个不等式解集区间加,最后前缀和还原,值等于 mm 的位置就是满足不等式的 aqaq。至于不合法解,我们考虑预处理 [n−m+1,n−1][n-m+1,n-1] 的不合法 qq 对应的 aqaq,在统计 aqaq 时,减去在其中的不合法值,此操作双指针扫描即可。

    代码实现需要注意的地方:

    • 在差分过程中注意 l>rl>r 的情况,这就是上文所说的两个区间的解集。
    • 求 l,rl,r 的时候进行减法可能出现负数,要加上 nn 后再对其取模。

    参考代码:

    #include<bits/stdc++.h>
    #define LL long long
    #define UN unsigned
    using namespace std;
    //--------------------//
    const int N=1e6+5,N2=2e6+5;
    
    int n,a,b,p,m,s[N];
    char str[N];
    int tcnt,sum[N2],de[N];
    LL tp[N2];
    LL l[N],r[N];
    //--------------------//
    int main()
    {
        scanf("%d%d%d%d%d%s",&n,&a,&b,&p,&m,str+1);
        for(int i=1;i<=m;i++)
        {
            s[i]=str[i]-'0';
            if(s[i])//求 l,r
            {
                l[i]=((p-1LL*a*(i-1)%n-b)%n+n)%n;
                r[i]=((n-1LL*a*(i-1)%n-b)%n+n)%n;
            }
            else
            {
                l[i]=((0-1LL*a*(i-1)%n-b)%n+n)%n;
                r[i]=((p-1LL*a*(i-1)%n-b)%n+n)%n;
            }
            tp[++tcnt]=l[i],tp[++tcnt]=r[i];
        }
        tp[++tcnt]=0,tp[++tcnt]=n;
        sort(tp+1,tp+tcnt+1);
        tcnt=unique(tp+1,tp+tcnt+1)-tp-1;
        for(int i=1;i<=m;i++)
        {
            l[i]=lower_bound(tp+1,tp+tcnt+1,l[i])-tp;
            r[i]=lower_bound(tp+1,tp+tcnt+1,r[i])-tp;
            sum[l[i]]++,sum[r[i]]--,sum[1]+=(l[i]>r[i]);//离散后差分
        }
        int ans=0,cnt=0;
        for(int i=2;i<=tcnt;i++)
            sum[i]+=sum[i-1];
        for(int i=n-m+1;i<n;i++)
            de[++cnt]=1LL*a*i%n;//预处理不合法解
        sort(de+1,de+cnt+1);
        for(int now=0,las,i=1;i<tcnt;i++)
        {
            las=now;
            while(now+1<=cnt&&de[now+1]<tp[i+1])//双指针扫描在符合条件 aq 中的不合法区间
                now++;
            if(sum[i]==m)
                ans+=tp[i+1]-tp[i]-(now-las);
        }
        printf("%lld",ans);
        return 0;
    }
    
    • 1

    [POI 2015 R2] 快速阅读课程 Speed reading course

    信息

    ID
    6042
    时间
    1000ms
    内存
    228MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者