zoukankan      html  css  js  c++  java
  • bzoj3326: [Scoi2013]数数

    Description

    Fish 是一条生活在海里的鱼,有一天他很无聊,就开始数数玩。
    他数数玩的具体规则是:
    1. 确定数数的进制B
    2. 确定一个数数的区间[L, R]
    3. 对于[L, R] 间的每一个数,把该数视为一个字符串,列出该字符串的每一个(连续的)子串对应的B进制数的值。
    4. 对所有列出的数求和。
    现在Fish 数了一遍数,但是不确定自己的结果是否正确了。由于[L, R] 较大,他没有多余精力去验证是否正确,你能写一个程序来帮他验证吗?

    Input

    输入包含三行。
    第一行仅有一个数B,表示数数的进制。
    第二行有N +1 个数,第一个数为N,表示数L 在B 进制下的长度为N,接下里的N个数从高位到低位的表示数L 的具体每一位。
    第三行有M+ 1 个数,第一个数为M,表示数R 在B 进制下的长度为M,接下里的M个数从高位到低位的表示数R 的具体每一位。

    20% 数据,0 <= R <= L <= 10^5。
    50% 数据,2 <= B <= 1000,1 <= N,M <= 1000。
    100% 数据,2 <= B <= 10^5,1 <= N,M <= 10^5。

    Output

    输出仅一行,即按照Fish 数数规则的结果,结果用10 进制表示,由于该数可能很大,输出该数模上20130427的模数。
    数位dp
    #include<bits/stdc++.h>
    typedef unsigned long long u64;
    const int P=20130427,N=2e5+77;
    char buf[100001],*ptr=buf+100000;
    int G(){
        if(ptr-buf==100000)fread(ptr=buf,1,100000,stdin);
        return *ptr++;
    }
    int _(){
        int x=0;
        if(ptr-buf<99900){
            while(*ptr<48)++ptr;
            while(*ptr>47)x=x*10+*ptr++-48;
        }else{
            int c=G();
            while(c<48)c=G();
            while(c>47)x=x*10+c-48,c=G();
        }
        return x;
    }
    int fix(int x){return x+(x>>31&P);}
    struct num{
        int a;
        num(int x=0):a(x){}
        num operator+(num x){return fix(a+x.a-P);}
        num operator-(num x){return fix(a-x.a);}
        num operator*(num x){return u64(a)*x.a%P;}
    };
    num S(num l,num r){
        return (u64(l.a+r.a)*(r.a-l.a+1)>>1)%P;
    }
    int B,n,m;
    int ns[N],ms[N];
    num v0[N],v1[N],pw[N],ps[N],f0[N][3],f1[N][3];
    num cal(int*a,int n){
        num s=0,r0=0,r1=0;
        for(int i=1;i<n;++i)s=s+(v1[i-1]+v0[i-1])*(B-1)+S(1,B-1)*ps[i-1]*pw[i-1];
        for(int i=n;i;--i){
            int L=(i==n),R=a[i]-1;
            if(L<=R){
                num D=R-L+1;
                num z0=v0[i-1]*D+S(L,R)*ps[i-1]*pw[i-1];
                num z1=v1[i-1]*D+z0;
                s=s+z1+(r1+r0*(ps[i]-1))*D*pw[i-1]+z0*(n-i);
            }
            r0=r0*B+num(a[i])*(n-i+1);
            r1=r1+r0;
        }
        return s;
    }
    int main(){
        B=_();
        n=_();
        for(int i=n;i;--i)ns[i]=_();
        m=_();
        for(int i=m;i;--i)ms[i]=_();
        ++ms[1];
        for(int i=1;ms[i]==B;++ms[i+1],ms[i]=0,++i);
        if(ms[m+1])++m;
        ps[0]=pw[0]=1;
        for(int i=1;i<=n||i<=m;++i){
            pw[i]=pw[i-1]*B;
            ps[i]=ps[i-1]+pw[i];
            v0[i]=v0[i-1]*B+S(0,B-1)*ps[i-1]*pw[i-1];
            v1[i]=v1[i-1]*B+v0[i];
        }
        printf("%d
    ",(cal(ms,m)-cal(ns,n)).a);
        return 0;
    }
  • 相关阅读:
    站立会议04(第二阶段)附加站立会议02、03
    第二阶段冲刺---站立会议01
    网络:Session原理及存储
    网络:Xen理解
    网络:LVS负载均衡原理
    网络:OSPF理解
    语音笔记:信号分析
    语音笔记:CTC
    语音笔记:矢量量化
    语音笔记:MFCC
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7122533.html
Copyright © 2011-2022 走看看