[AHOI2009]同类分布

[AHOI2009]同类分布

求区间\([l,r]\)内的数,满足自己能整除自己各个数位上的和的数的个数,\(l,r\leq 10^{18}\)。

不难得知设\(f_n\)为n以内的满足条件的数,答案即\(f_r-f_l\),因为递推中要表现整除,可以考虑摸递推。

要表现各个数位的和,又要变现长度,而且还要表现摸数,还有余数,故设\(f[i][j][k][l]\)表示i位的数,各数位的和为j,摸数为k,余数为l的数的方案数,因此不难有

\[f[i][j][k][l]=\sum_{p=0}^9\{f[i-1][j-p][k][(l-p)\%k]\}\]

边界:\(f[0][0][k][0]=1,k=0,1,2,...,162\)

注意到空间开不下,而摸数不涉及转移,故可以压掉,于是我们可以枚举各位和,临时求递推方程,来进行试填,没有其他的什么细节了,因为时间复杂度理论是不能过了,注意看起来不起眼的剪枝。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define ll long long
using namespace std;
int num[20];
ll dp[20][200][200],base[20];
il ll ask(ll,int);
il int min(int,int);
template<class f1,class f2>
il f1 mod(f1,f2&);
int main(){
    int i;ll ans(0),a,b;
    scanf("%lld%lld",&a,&b);
    for(i=base[0]=1;i<19;++i)base[i]=base[i-1]*10;
    for(i=1;i<163;++i)
        ans+=ask(b,i)-ask(a-1,i);
    printf("%lld\n",ans);
    return 0;
}
il int min(int a,int b){
    return a<b?a:b;
}
il ll ask(ll n,int k){
    ri int i,j,r;ri ll l;ll ans(0);
    memset(num,0,sizeof(num));
    memset(dp,0,sizeof(dp)),++n;
    while(n)num[++num[0]]=n%10,n/=10;
    dp[0][0][0]=1;
    for(i=0;i<num[0];++i)
        for(j=0;j<=k;++j)
            for(l=0;l<k;++l)
                if(dp[i][j][l])
                    for(r=0;r<10;++r)
                        dp[i+1][j+r][(l+r*base[i])%k]+=dp[i][j][l];
    r=k,l=0;
    for(i=num[0];i;--i){
        for(j=0;j<num[i]&&j<=r;++j)
            ans+=dp[i-1][r-j][mod(l-j*base[i-1],k)];
        r-=j,l=mod(l-j*base[i-1],k);
    }return ans;
}
template<class f1,class f2>
il f1 mod(f1 x,f2 &y){
    return ((x%=y)+=y)%=y;
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/10992513.html

时间: 2024-11-02 19:30:39

[AHOI2009]同类分布的相关文章

【题解】AHOI2009同类分布

好开心呀~果然只有不看题解做出来的题目才会真正的有一种骄傲与满足吧ヾ(????)?" 实际上这题只要顺藤摸瓜就可以了.首先按照数位dp的套路,有两维想必是省不掉:1.当前dp到到的位数:2.0/1状态表示是否受限制(这一条是因为有数字上限).然后根据这两个维度来接着往下想.第二个维度先撇开不看,我们只考虑如何从第 \(i - 1\) 位dp到第 \(i\) 位.在这里其实卡了有点久,因为如果除数与被除数都在改变,那么两维的转移是非常凉凉的. 这个时候联想题目的特殊性质 ----- 当感觉无法优化

P4127 [AHOI2009]同类分布

链接:https://www.luogu.org/problemnew/show/P4127 题目描述 给出两个数 a,ba,b ,求出 [a,b][a,b] 中各位数字之和能整除原数的数的个数. 输入输出格式 输入格式: 一行,两个整数 aa 和 bb 输出格式: 一个整数,表示答案 输入输出样例 输入样例#1: 复制 10 19 输出样例#1: 复制 3 说明 对于所有的数据, 1 ≤ a ≤ b ≤ 10^18 题解:数位dp, 但有一个问题,我们不知道各个数位数字之和:18*9是很小的,

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

传送门 Solution 裸数位dp,空间存不下只能枚举数字具体是什么 注意memset最好为-1,不要是0,有很多状态答案为0 Code //By Menteur_Hxy #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define Re registe

【数位DP】【P4127】[AHOI2009]同类分布

Description 给出两个数 \(a,~b\) 求出 \([a~,b]\) 中各位数字之和能整除原数的数的个数. Limitations \(1 \leq a,~b \leq 10^{18}\) Solution 考虑数位DP. 设数字 \(A = \sum_{i = 0}^k a_i \times 10^i\),其数字和 \(B = \sum_{i = 0}^k a_i\) 那么 \(A\) 满足条件即为 \(A \equiv 0 \pmod B\),根据同余的性质,可以将求和符号拆开:

bzoj 1799: [Ahoi2009]self 同类分布 题解

[原题] 1799: [Ahoi2009]self 同类分布 Time Limit: 50 Sec  Memory Limit: 64 MB Submit: 554  Solved: 194 [Submit][Status] Description 给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数. Input Output Sample Input 10 19 Sample Output 3 HINT [约束条件]1 ≤ a ≤ b ≤ 10^18 Source Day1 [分析]

HYSBZ - 1799 self 同类分布

self 同类分布 HYSBZ - 1799 给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数.Sample Input 10 19 Sample Output 3 Hint [约束条件]1 ≤ a ≤ b ≤ 10^18 约束:一个数是它自己数位和的倍数,直接dp根本找不到状态,枚举数位和,因为总就162,然后问题就变成了一个数%mod=0,mod是枚举的,想想状态:dp[pos][sum][val],当前pos位上数位和是sum,val就是在算这个数%mod,(从高位算  *10

BZOJ1799 self 同类分布 数位dp

BZOJ1799self 同类分布 题意 给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数. [约束条件]1 ≤ a ≤ b ≤ 10^18 题解 1.所有的位数之和<9*18=1622.所以,dp[i][j][k][m]表示有i位(允许有前导0),数位和为k,模数为m,前i位与模数的模为j的符合条件的数的个数.这样要炸空间,怎么办!!其实这个dp的最后一维可以省去,因为对于不同的m值,dp互不相干.这样还是要超时的,有5亿多.于是就要卡常数,具体见代码里面的枚举的上下界. 代码 #

【BZOJ】1799: [Ahoi2009]self 同类分布

[题意]给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数.1 ≤ a ≤ b ≤ 10^18 [算法]数位DP [题解] 感觉这种方法很暴力啊. 枚举数位和1~162(不能枚举0,不然会模0,相当于除0),记忆化f[pos][sum][val],sum表示当前数位和,val表示数字取模枚举的数位和. 每次sum+i和(val*10+i)%MOD转移. sum用减法优化,即记忆化(MOD-sum),但是枚举过程中都要memset,导致效率低下,记忆化效果很差. 要什么方法才能跑1.3s

bzoj1799 [Ahoi2009]self 同类分布

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1799 [题解] 一眼看过去,数位dp! 想了想,发现数字和最多也就是$m = 9 \times 18 = 162$种,好像不是很大. 考虑枚举每种数字和$p$,做一遍dp. 设$f_{i,j,k}$表示到第$i$位,当前真实数字模$p$余$j$,当前所有数字的和为$k$的方案数.(不考虑前导0问题) 这个可以通过一个$O(18\times p^2 \times 10)$的动态规划解决. 接