1 条题解

  • 0
    @ 2025-8-24 22:05:34

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ycyaw
    无他,唯勤尔

    搬运于2025-08-24 22:05:34,当前版本为作者最后更新于2019-11-08 18:06:12,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    来一个dfsdfs版的数位dpdp

    这种统计和的数位dpdp,相对于统计个数的数位dpdp,既要记录个数,又要记录和。然后对于每一位,累加个数乘以这一位位置的贡献,即百位就是个数乘以100100,千位就是乘以10001000,依此类推。

    有一个地方被坑了好久,不能用的数字我拿数组记下来,然后在枚举当前位的时候,没有判前导零,也就是如果零不能用,前导零我就不会枚举到。调了一年。。

    没有什么思维难度,考察了数位dpdp模板的掌握程度。

    Code Below:Code\ Below:

    #include<bits/stdc++.h>
    #define ts cout<<"ok"<<endl
    #define int long long
    #define hh puts("")
    #define pc putchar
    //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    //char buf[1<<21],*p1=buf,*p2=buf;
    using namespace std;
    int s1,s2,nd,no,l,r,a[15],mi[15];
    struct node{
        int cnt,sum;
    }dp[16][1<<10];
    inline int read(){
        int ret=0,ff=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)){ret=ret*10+(ch^48);ch=getchar();}
        return ret*ff;
    }
    void write(int x){if(x<0){x=-x,pc('-');}if(x>9) write(x/10);pc(x%10+48);}
    void writeln(int x){write(x),hh;}
    void writesp(int x){write(x),pc(' ');}
    node dfs(int pos,int zt,int lead,int lim){
        if(!pos){
            if((zt&nd)==nd&&(zt&no)==0) return (node){1,0};
            return (node){0,0};
        }
        if(!lead&&!lim&&dp[pos][zt].sum!=-1) return dp[pos][zt];
        int mx=lim?a[pos]:9;
        node res=(node){0,0};
        for(int i=0;i<=mx;i++){
            node t;
            if(lead&&!i) t=dfs(pos-1,zt,1,lim&&(i==mx));
            else t=dfs(pos-1,zt|(1<<i),0,lim&&(i==mx));
            res.cnt+=t.cnt;
            res.sum+=t.sum+t.cnt*i*mi[pos-1];
        }
        if(!lead&&!lim) dp[pos][zt]=res;
        return res;
    }
    int work(int x){
        if(!x) return 0;
        int len=0;
        while(x){
            a[++len]=x%10;
            x/=10;
        }
        return dfs(len,0,1,1).sum;
    }
    signed main(){
        mi[0]=1;
        for(int i=1;i<=15;i++) mi[i]=mi[i-1]*10;
        int T=read();
        while(T--){
            memset(dp,-1,sizeof(dp));
            l=read(),r=read();
            nd=no=0;
            s1=read();
            for(int i=1;i<=s1;i++) nd|=1<<(read());
            s2=read();
            for(int i=1;i<=s2;i++) no|=1<<(read());
            writeln(work(r)-work(l-1));
        }
        return 0;
    }
    
    • 1

    信息

    ID
    3952
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    (无)
    递交数
    0
    已通过
    0
    上传者