题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=5443

题目大意

令两个序列为k-相似,当且仅当k为两个序列对应位置上不同的值的个数,例如1 2 3 41 3 3 3为2-相似,因为两个序列2位置与4位置是不同的。现有一个长度为n的序列,可以将它划分为长度为LnL+1个子串。Q组询问,求每个子串与多少个其他子串为ki相似。

Ln104,Q102,空间32MB。

题解

考虑不卡空间的做法,令f[i][j]表示i子串与其他子串有多少个j-相似的。转移时枚举两个子串开始位置的间隔,若开始位置+1,那么相似-原开始位置是不是相同的+新结束位置是不是相同的。最后前缀和求j的和

现在考虑卡空间的做法,如果询问的是2,6,8,那么一个子串与另一个子串4-相似,实际上只会对询问6,8产生影响,离线存下所有询问,修改操作就直接找到第一个它的询问,在询问上面修改,最后还是前缀和。

代码

#include <cstdio>
#include <algorithm>

int read()
{
    int x=0,f=1;
    char ch=getchar();
    while((ch<'0')||(ch>'9'))
    {
        if(ch=='-')
        {
            f=-f;
        }
        ch=getchar();
    }
    while((ch>='0')&&(ch<='9'))
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

int print(int x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x/10)
    {
        print(x/10);
    }
    putchar('0'+x%10);
    return 0;
}

const int maxn=10000;
const int maxq=100;

struct query
{
    int val,pre_id,ans_id;

    bool operator <(const query &other) const
    {
        return val<other.val;
    }
};

bool cmp(const query &a,const query &b)
{
    return a.pre_id<b.pre_id;
}

query q[maxq+10];
int ans[maxq+10][maxn+10],ak[maxq+10],v[maxn+10],n,l,m,pos[maxn+10];

int main()
{
    n=read();
    l=read();
    for(int i=1; i<=n; ++i)
    {
        v[i]=read();
    }
    m=read();
    for(int i=1; i<=m; ++i)
    {
        q[i].val=read();
        q[i].pre_id=i;
    }
    std::sort(q+1,q+m+1);
    for(int i=1; i<=m; ++i)
    {
        q[i].ans_id=i;
        ak[i]=q[i].val;
    }
    for(int i=0; i<=l; ++i)
    {
        pos[i]=std::lower_bound(ak+1,ak+m+1,i)-ak;
    }
    for(int i=1; i<=n-l; ++i)
    {
        int diff=0;
        for(int j=1; j<=l; ++j)
        {
            if(v[j]!=v[j+i])
            {
                ++diff;
            }
        }
        int p=pos[diff];
        ++ans[p][1];
        ++ans[p][1+i];
        for(int j=2; j+i+l-1<=n; ++j)
        {
            diff=diff-(v[j-1]!=v[j-1+i])+(v[j+l-1]!=v[j+i+l-1]);
            p=pos[diff];
            ++ans[p][j];
            ++ans[p][j+i];
        }
    }
    for(int i=1; i<=m; ++i)
    {
        for(int j=1; j<=n; ++j)
        {
            ans[i][j]+=ans[i-1][j];
        }
    }
    std::sort(q+1,q+m+1,cmp);
    for(int i=1; i<=m; ++i)
    {
        for(int j=1; j+l-1<=n; ++j)
        {
            print(ans[q[i].ans_id][j]);
            putchar(' ');
        }
        putchar('\n');
    }
    return 0;
}