zoukankan      html  css  js  c++  java
  • 模拟赛 数根 题解

    题意:
    对于一个(B)进制数(x)定义它的数根为把所有位上的数加在一起的结果。
    给出一个长度为(n)(B)进制串(s)(m)次询问每次给定一个集合(A)和一个数(x),计算有多少个(s[l ... r])可以通过将至多一个字符更改为(A)中的元素使得数根为(x)

    (n,mleq 2^{20},B<=16),时间限制8s。

    首先,考虑快速求一个数的数根(f(x))

    (B)进制数(x=sum_{i=0}^{n}a_iB^i)(y=sum_{i=0}^{n}a_i)。那么(y-x=sum_{i=0}^{n}a_i(B^i-1))。由等比数列求和公式,(B-1|B^i-1)。因此(xequiv y mod B-1),即(xequiv f(x) mod B-1)

    那么维护总和模(B-1)(x)的区间数量,就可以处理不进行修改的情况。

    对于修改操作,假设一个区间原来的总和模(B-1)(y),那么只要把其中的一个数字增加(t=x-y),就能满足条件。

    设给出的集合为(A),再设(C={x|x+tin A}),那么只要这个总和为(y)的区间内元素的集合与(C)的交集不为空,这个区间就满足条件。

    我们只要对于所有(0leq y<B-1)和所有集合(S)求出总和为(y),区间内元素集合为(S)的区间数目,对于交集不为空这个条件用(FMT)预处理一下就行。

    对于这个子问题,我们可以枚举右端点(r),并对于每个(x)维护从(r)往左第一个等于(x)的位置。这些位置把序列分为了若干段,每一段的(S)都是相等的。

    对于每一段分别求即可。

    这个使用前缀和即可优化至(O(nB^2))

    现在我们已经解决了大部分情况,但是还有几个细节:

    首先,对于(x=0)的询问,要求区间内都是0。这个我们可以维护全是(0)的以及只有一个非零位置的区间个数来计算。

    对于(x=B-1)的询问,需要考虑把所有数字都改为0的情况。

    (B-1 otin A),那么全是0的需要减去。同时若(0in A),那么长度为1的元素不为0的区间应当减去。

    并且对于只有一个非零(x)的长度至少为2的区间,若(B-1-x otin A),那么这个也得减去。

    总时间复杂度为(O((n+m)*B^2))。能过。

    参考代码:

    #include <stdio.h>
    #include <string.h>
    #define ll long long
    char zf[1048580];int ch[300],su[1048580];
    int sz[1048580],la[16],he[16][1048580];
    void swap(int &a,int &b)
    {
        int t=a;a=b;b=t;
    }
    void fmt(ll sz[32768],int B)
    {
        for(int j=0;j<B;j++)
        {
            for(int i=0;i<(1<<B);i++)
            {
                if(i&(1<<j))
                    sz[i]+=sz[i^(1<<j)];
            }
        }
    }
    ll ss[16][32768],s1[16];int cs[16];
    int main()
    {
        freopen("number.in","r",stdin);
        freopen("number.out","w",stdout);
        int n,m,B;ll s0=0;
        scanf("%d%d%d%s",&n,&m,&B,zf);
        for(int i=0;i<10;i++)
            ch[i+'0']=i;
        for(int i=0;i<6;i++)
            ch[i+'a']=i+10;
        he[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            sz[i]=ch[zf[i-1]];
            cs[sz[i]]+=1;
            su[i]=(su[i-1]+sz[i])%(B-1);
            for(int j=0;j<B-1;j++)
                he[j][i]=he[j][i-1];
            he[su[i]][i]+=1;
        }
        for(int r=1,l1=0,l2=0;r<=n;r++)
        {
            if(sz[r]){l1=l2;l2=r;}
            s0+=r-l2;
            if(l2)s1[sz[l2]]+=l2-l1-(l2==r);
            la[sz[r]%(B-1)]=r;int px[17],pz[17];
            for(int i=0;i<B-1;i++)
                px[i]=la[i],pz[i]=i;
            px[B-1]=0;
            for(int i=0;i<B-1;i++)
            {
                for(int j=i+1;j<B-1;j++)
                {
                    if(px[i]<px[j])
                        swap(px[i],px[j]),swap(pz[i],pz[j]);
                }
            }
            for(int i=0,z=0;i<B-1&&px[i];i++)
            {
                z|=(1<<pz[i]);
                for(int j=0;j<B-1;j++)
                {
                    int t=(su[r]-j+B-1)%(B-1);
                    ss[j][z]+=he[t][px[i]-1];
                    if(px[i+1])ss[j][z]-=he[t][px[i+1]-1];
                }
            }
        }
        for(int i=0;i<B-1;i++)fmt(ss[i],B-1);
        for(int i=0;i<m;i++)
        {
            char xx[2],zz[20];bool bk[16]={0};
            scanf("%s%s",xx,zz);
            int x=ch[xx[0]],s=strlen(zz);
            for(int j=0;j<s;j++)bk[ch[zz[j]]]=true;
            if(x==0)
            {
                ll ans=s0;
                if(bk[0])
                {
                    for(int j=1;j<B;j++)
                        ans+=cs[j]+s1[j];
                }
                printf("%lld
    ",ans);
                continue;
            }
            ll ans=ss[x%(B-1)][(1<<(B-1))-1];
            for(int y=0;y<B-1;y++)
            {
                if(x%(B-1)==y)continue;
                int t=(x-y+B-1)%(B-1),z=0;
                for(int j=0;j<s;j++)
                    z|=(1<<((ch[zz[j]]-t+B-1)%(B-1)));
                ans+=ss[y][(1<<(B-1))-1];
                ans-=ss[y][((1<<(B-1))-1)^z];
            }
            if(x==B-1&&!bk[B-1])
            {
                ans-=s0;
                if(bk[0])
                {
                    for(int j=1;j<B-1;j++)
                    {
                        ans-=cs[j];
                        if(!bk[B-1-j])ans-=s1[j];
                    }
                }
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    static用法
    Spring相关配置及工厂模式
    Mybatis的相关配置及理解
    jsp内置对象简介
    JAVA基础——接口的理解
    JAVA基础——抽象类以及final修饰符总结
    关于JAVA基础 ——继承的总结
    封装
    static的用法
    构造方法的重载
  • 原文地址:https://www.cnblogs.com/lnzwz/p/14623471.html
Copyright © 2011-2022 走看看