bzoj1799 数位dp

Posted %%%%%

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1799 数位dp相关的知识,希望对你有一定的参考价值。

HYSBZ - 1799

题意:给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。

思路:数位dp,比较容易想到是数位dp,关键是dp式比较难想到,数位dp说到底是一个记忆化搜索的过程,dp式是一个记忆数组,对于一类数来说,对应了一个dp式,并且他们的答案是一样的,那么可以通过只对一个经行搜索然后得到全部的答案,这其实就是一个状态,这个状态首先要保证与其他状态没有交集,并且要保证状态数不能过多,否则记忆化效果不好,比如1e18个数用1e5个状态来表示显然可以大大降低复杂度,时间上是没有问题的,但是如果状态答道了1e15就是一个非常糟糕的状态表示了,这个题的难点就是找状态,dp[pos][sum][v],第一维表示数位不用说,第二维表示前pos位的数位和,v表示这个数%mod的值,这个mod是枚举的,从1-162枚举, 比如 123xxxx枚举mod=5对应的dp式为dp[4][6][123%5],显然对于前3位和为6并且模的结果为3的状态的所有数来说答案是一样的,这里有一点,这里说的”答案“ 是指前几位已经确定,后面几位不确定,但是由已确定的前几位可以推出后面几位不确定的所有情况中可行的情况,比如123xx 一共存在100种可能性,其中12345是可行的,而12346是不可行的

AC代码:

#include "iostream"
#include "iomanip"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#pragma comment(linker, "/STACK:102400000,102400000")
#define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
#define mem(a,x) memset(a,x,sizeof(a))
#define step(x) fixed<< setprecision(x)<<
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define ll long long
#define endl ("\n")
#define ft first
#define sd second
#define lrt (rt<<1)
#define rrt (rt<<1|1)
using namespace std;
const ll mod=1e9+7;
const ll INF = 1e18+1LL;
const int inf = 1e9+1e8;
const double PI=acos(-1.0);
const int N=1e5+100;

ll dp[18][162][162], bit[20];
ll dfs(int limit, int pos, int sum, int v, int mod){
    if(sum+pos*9+9<mod || sum>mod) return 0;
    if(pos==-1) return sum==mod && v==0;
    if(dp[pos][sum][v]!=-1 && !limit) return dp[pos][sum][v];
    int up=limit?bit[pos]:9;
    ll ans=0;
    for(int i=0; i<=up; ++i){
        ans+=dfs(limit&&i==bit[pos], pos-1, sum+i, (v*10+i)%mod, mod);
    }
    if(!limit) dp[pos][sum][v]=ans;
    return ans;
}

ll solve(ll x){
    int p=0;
    while(x){
        bit[p++]=x%10;
        x/=10;
    }
    ll ret=0;
    for(int i=1; i<=p*9; ++i){
        mem(dp,-1);
        ret+=dfs(1,p-1,0,0,i);
    }
    return ret;
}

int main(){
    ll a,b;
    scanf("%lld%lld",&a, &b);
    printf("%lld\n",solve(b)-solve(a-1));
    return 0;
}

 

以上是关于bzoj1799 数位dp的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1799 self 同类分布 数位dp

BZOJ 1799 同类分布(数位DP)

bzoj 1799 [Ahoi2009]self 同类分布(数位DP)

BZOJ 1799: [Ahoi2009]self 同类分布 ( 数位dp )

BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin

BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin