zoukankan      html  css  js  c++  java
  • [BZOJ 3326] 数数

    Link:

    BZOJ 3326 传送门

    Solution:

    明显是一道数位$dp$的题目,就是递推式复杂了点

    先要求出一个数$ar{n}$向添加一位后的$ar{np}$的转化关系

    令$res[ar{n}]$为数$n$的权值和,

    则$res[ar{np}]=res[ar{n}]+sum_{i=1}^{len(n)} ar{n[i...len(n)]p}$

    令$suf[ar{n}]$为数$n$的后缀和,

    则$res[ar{np}]=res[ar{n}]+suf[ar{np}]$

    同时$suf$自己的递推式为:$suf[ar{np}]=base*suf[ar{n}]+(len(n)+1)*p$

    再令$dgt[ar{n}]$为数$n$的位数,

    则$dgt[ar{np}]=dgt[ar{n}]+1$

    上面的递推式虽然都只针对某一个数$n$,但完全可以逐层推广到之前所有数的和

    使原来的$res,suf,dgt$分别表示$sum res,sum suf,sum dgt$,$a$表示数的个数

    再用第二维的$0/1$表示是否达到上界,算是数位$dp$的常规套路

    剩下的递归式还是看代码吧……

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAXN=1e5+10,MOD=20130427;
    
    int B,l1,l2,dat1[MAXN],dat2[MAXN];
    ll pre[MAXN],res[MAXN][2],a[MAXN][2],suf[MAXN][2],dgt[MAXN][2];
    
    ll solve(int *dat,int l)
    {
        memset(res,0,sizeof(res));memset(dgt,0,sizeof(dgt));
        memset(a,0,sizeof(a));memset(suf,0,sizeof(suf));
        
        a[l+1][0]=1;
        for(int i=l;i;i--)
        {
            int cur=(i==l)?0:B;
            
            a[i][0]=a[i+1][0];
            a[i][1]=((cur-1)+a[i+1][1]*B+a[i+1][0]*dat[i])%MOD;
            dgt[i][0]=(dgt[i+1][0]+a[i+1][0])%MOD;
            dgt[i][1]=((cur-1)+(dgt[i+1][1]+a[i+1][1])*B%MOD+(dgt[i+1][0]+a[i+1][0])*dat[i]%MOD)%MOD;
            suf[i][0]=(suf[i+1][0]*B+dgt[i][0]*dat[i])%MOD;
            suf[i][1]=(pre[cur]+(suf[i+1][1]*B%MOD*B%MOD+(dgt[i+1][1]+a[i+1][1])*pre[B]%MOD)+
                       (suf[i+1][0]*B*dat[i]%MOD+dgt[i][0]*pre[dat[i]]%MOD))%MOD;
            res[i][0]=(res[i+1][0]+suf[i][0])%MOD;
            res[i][1]=(res[i+1][0]*dat[i]%MOD+res[i+1][1]*B%MOD+suf[i][1])%MOD;
        }
        return (res[1][0]+res[1][1])%MOD;
    }
    
    int main()
    {
        scanf("%d",&B);
        for(int i=1;i<=B;i++) pre[i]=(pre[i-1]+i-1)%MOD;
        
        scanf("%d",&l1);
        for(int i=l1;i>=1;i--) scanf("%d",&dat1[i]);
        scanf("%d",&l2);
        for(int i=l2;i>=1;i--) scanf("%d",&dat2[i]);
        
        for(int i=1;i<=l1;i++)
            if(dat1[i]){dat1[i]--;break;}
            else dat1[i]=B-1;
        if(!dat1[l1]) l1--;
        
        printf("%lld",(solve(dat2,l2)-solve(dat1,l1)+MOD)%MOD);
        return 0;
    }
  • 相关阅读:
    使用 Traefik 代理 UDP 服务
    KubeOperator界面,集群详情中的存储,存储提供商
    centos7使用yum方式安装node_exporter
    Traefik2.3.x 使用大全(更新版)
    jumpserver堡垒机版本升级,从2.14.2升级到2.16.3
    Traefik 2.0 实现灰度发布
    matplotlib 中文问题
    数据采集实战(五) 当当网童书排名
    雅可比行列式迭代及优化(golang版)
    mysql8.x docker 远程访问配置
  • 原文地址:https://www.cnblogs.com/newera/p/9324576.html
Copyright © 2011-2022 走看看