zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 53 (Rated for Div. 2) E. Segment Sum

    https://codeforces.com/contest/1073/problem/E

    题意

    求出l到r之间的符合要求的数之和,结果取模998244353
    要求:组成数的数位所用的数字种类不超过k种

    思路

    这题一看就是个数位dp的模板题,但是由于以前没有完全理解数位dp加上xjb套模版,导致样例都没算出来

    • 一开始这样定义状态

      dp[i][j] 代表第cnt~i(高位到低位)位,cnt~i状态为j的总和

    • 一直记录当前数字的数值,到边界的时候返回加到答案中,但是由于这样定义状态会导致一个状态对应多个数,但是他只能累加字典序最小的数到答案中,所以会使得有的数并没有被计算

    • 仔细分析一波,回归dp本身,应该找到一个子状态,使得后面的状态可以通过前面的状态计算得到(转移),其实只需要改一下定义

      dp[i][j] 代表0i(低位到高位),cnti+1状态为j的总和sum和数字个数num(dp两个东西)
      在第i步选择第i位的数字

    • 其实就是转换一下计算方法,比如0~9可以加在数字1后,组成10~19,转化为公式(10^{i-1}*dp[i-1][j|(1<<digit)].num*digit)

    • 转移为:(dp[i][j]=sum_{digit=0}^{9}(dp[i][j].sum+10^{i-1}*dp[i-1][j|(1<<digit)].num*digit))

    关于数位dp

    • 对于每个数求出的是小于这个数的所有满足条件的数(前缀和)
      • 将一个数当成字符串,然后从高位往低位看,lead看前导0是否对计数产生影响
      • 通常定义状态可以理解为

      dp[i][j] 代表0i(低位到高位),cnti+1状态为j的计数

    • 关于lead和limit,可以放在数组下标,也可以在函数里特判

    附上一个lead和limit在函数中特判的板子

    #include<bits/stdc++.h>
    #define ll long long 
    #define P 998244353
    #define M 2005
    using namespace std;
    struct N{
        ll x,y;
    }dp[25][M];
    ll pw[25],l,r;
    int k,a[25],i,cnt;
    
    N dfs(int p,int st,int lead,int limit){
        if(!p) return __builtin_popcount(st)<=k&&!lead?N{1,0}:N{0,0};
        if(!lead&&!limit&&dp[p][st].y!=-1)return dp[p][st];
        N ans=N{0,0};
        int end=(limit?a[p]:9);
        for(int i=0;i<=end;i++){
           N tp=dfs(p-1,lead&&!i?0:st|(1<<i),lead&&!i,limit&&i==end);
           ans.x=(ans.x+tp.x)%P;
           ans.y=(ans.y+tp.y+1ll*i*pw[p-1]%P*tp.x%P)%P;
        }
        if(!limit)dp[p][st]=ans;
        return ans;
    }
        
    
    ll cal(ll x){
         cnt=0;
        while(x>0){a[++cnt]=x%10;x/=10;}
        memset(dp,-1,sizeof(dp));
        return dfs(cnt,0,1,1).y%P;
    }
    
    int main(){
        pw[0]=1;
        for(i=1;i<=20;i++)pw[i]=pw[i-1]*10%P;
        cin>>l>>r>>k;
        cout<<(cal(r)-cal(l-1)+P)%P;
    }
    
    
  • 相关阅读:
    shell去重
    JDBC源码解析
    try catch finally
    URL
    域名与IP地址的联系与区别
    C++stack
    C++vector
    单链表常见面试题(C语言实现)
    数据库limit子句
    strcpy和memcpy的区别
  • 原文地址:https://www.cnblogs.com/VIrtu0s0/p/9895573.html
Copyright © 2011-2022 走看看