DP_数位DP_数字游戏2

这道题可以加深对于数位DP预处理和分类讨论的理解。

题目数字游戏2

做法:动态规划
状态表示: f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示 i i i 位数,最高位是 j j j ,同时该数各位数字之和除 N N N 的余数是 k k k.
预处理(状态转移): f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] = = = ∑ x = 0 9 \sum_{x=0}^9 x=09 f [ i − 1 ] [ x ] [ ( k − x ) m o d N ] f[i-1][x][(k-x)modN] f[i1][x][(kx)modN]
选择集合:先累加在转移即可,具体步骤看代码,latex打太多令人烦躁…

代码及注释

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N=11,M=110;

int a,b,n;
int f[N][10][M];

int mod(int x,int y){
    return (x%y+y)%y;
}

void calf(){
    memset(f,0,sizeof(f));
    
    for(int i=0;i<=9;i++) f[1][i][mod(i,n)]++;       //f[i][j][k]表示i位数字,最高位是j,各位数字和mod N = k 的数字个数
    
    for(int i=2;i<N;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<n;k++)
                for(int x=0;x<=9;x++)
                    f[i][j][k]+=f[i-1][x][mod(k-j,n)];
    
}

int dp(int x){
    if(!x) return 1;
    
    vector<int> num;
    while(x) num.push_back(x%10),x/=10;
    
    int res=0;
    int last=0;
    
    for(int i=num.size()-1;i>=0;i--){
        int u=num[i];
        for(int j=0;j<u;j++)
            res+=f[i+1][j][mod(-last,n)];  //-last保证为 modN=0,i+1是数字有多少位,要加1因为vector从零开始
        last+=u;           //转移
        if(!i && last%n==0) res++;
    }
    
    return res;
    
}

int main(){
    while(cin>>a>>b>>n){
        calf();
        cout<<dp(b)-dp(a-1)<<endl;
    }
    
    return 0;
}

关于这道题,有两点记录:

1、处理每一位数本身时一定一定要注意细节:
a)vector 从后往前处理,要注意位数;
b)不要把选择该位填最大可填数的方案加入,直接转移到 last;
c)最后的一个要注意特判。

2、两点着重思考预处理和集合选择。

P.S. mod 必要时要自己写!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值