bzoj1799 luogu4127 同类分布

Posted w19567

tags:

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

1799: [Ahoi2009]self 同类分布

Time Limit: 50 Sec  Memory Limit: 64 MB
Submit: 2455  Solved: 1124
[Submit][Status][Discuss]

Description

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

Input

 

Output

 

Sample Input

10 19

Sample Output

3

HINT

【约束条件】1 ≤ a ≤ b ≤ 10^18

 

显然数位dp

一开始想的是设dp[pos][num][sum][mod][limit]表示满足各位数字之和为sum,原数模num为mod的pos位数的个数

然后空间复杂度20*200*200*200*2就爆掉了

然后发现其实对于第二维,每一次dfs的时候它都不会改变,一直传递下去

于是我们不妨省去这一维,每次改变num前将dp数组重新赋值为-1,再进行下一个num的dfs

转移方程:dp[pos][sum][mod][limit]=∑dp[pos][sum-i][(mod-i*10pos-1)%num][limit&(i==lim[pos])]

思路还是挺自然的......

 

#include<bits/stdc++.h>
using namespace std;
long long A,B;
int lim[20],cnt;
long long dp[20][200][200][2];
long long pow_10[20],ans;
long long dfs(int pos,int num,int sum,int ys,bool limit)

    if(sum<0) return 0;
    if(!pos && sum>0) return 0;
    if(dp[pos][sum][ys][limit]>-1) return dp[pos][sum][ys][limit];
    if(!pos) return 0;
    long long ret=0;
    int r=limit?lim[pos]:9;
    for(int i=0;i<=r;++i)
        ret+=dfs(pos-1,num,sum-i,((ys-pow_10[pos-1]*i)%num+num)%num,limit&(i==lim[pos]));
    dp[pos][sum][ys][limit]=ret;
    return ret;

void part(long long x,bool on)

    cnt=0;
    while(x)
    
        lim[++cnt]=(x%10);
        x/=10;
    
    for(int i=1;i<=cnt*9;++i)
    
        memset(dp,-1,sizeof(dp));
        dp[0][0][0][0]=dp[0][0][0][1]=1;
        if(!on) ans+=dfs(cnt,i,i,0,1);
        else ans-=dfs(cnt,i,i,0,1);
    

int main()

    pow_10[0]=1;
    for(int i=1;i<=18;++i) pow_10[i]=(pow_10[i-1]*10);
    scanf("%lld%lld",&A,&B);
    part(B,0); part(A-1,1);
    printf("%lld",ans);
    return 0;

 

 

以上是关于bzoj1799 luogu4127 同类分布的主要内容,如果未能解决你的问题,请参考以下文章

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

luogu P4127 [AHOI2009]同类分布 数位dp

luogu P4127 [AHOI2009]同类分布 数位dp

[luogu4127 AHOI2009] 同类分布 (数位dp)

[数位DP][AHOI2009] Luogu P4127 同类分布

BZOJ1799 self 同类分布 数位dp