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

传送门

 

也不是很难,微坑的一点是dp数组在扫描每一次数位和的时候都要初始化,

因为没有存 用来mod的总数位和x 的位置... ...

然后这个dp的式子也稍微想了一下...还是练题太少...

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std;
 8 const int upn=162;
 9 long long f[20][163][163]={};//k位 数位和 目前mod后值
10 long long shu[20]={};
11 long long a,b;
12 long long doit(int k,int x,int now,int modn,bool maxnum){
13     if(k==0){
14         return x==now&&modn==0;
15     }
16     if((!maxnum)&&f[k][x-now][modn]!=-1){
17         return f[k][x-now][modn];
18     }
19     int maxn=maxnum?shu[k]:9;
20     maxn=min(maxn,x-now);
21     int minn=0;
22     minn=max(minn,x-now-(k-1)*9);
23     long long ans=0;
24     int z;
25     for(int i=minn;i<=maxn;i++){
26         z=(modn*10+i)%x;
27         ans+=doit(k-1,x,now+i,z,maxnum&&i==shu[k]);
28     }
29     if(!maxnum){
30         f[k][x-now][modn]=ans;
31     }
32     return ans;
33 }
34 long long solve(long long x){
35     memset(shu,0,sizeof(shu));
36     memset(f,-1,sizeof(f));
37     if(x==0){
38         return 0;
39     }
40     int k=0;
41     while(x){
42         shu[++k]=x%10;
43         x/=10;
44     }
45     long long cnt=0;
46     for(int i=1;i<=9*k;i++){
47         cnt+=doit(k,i,0,0,1);
48     }
49     return cnt;
50 }
51 int main(){
52     memset(f,-1,sizeof(f));
53     scanf("%lld%lld",&a,&b);
54     printf("%lld\n",solve(b)-solve(a-1));
55     return 0;
56 }

时间: 2024-10-24 20:41:41

BZOJ 1799: [Ahoi2009]self 同类分布 ( 数位dp )的相关文章

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 [分析]

bzoj 1799: [Ahoi2009]self 同类分布

数位DP|记忆化搜索 听隔壁巨佬说DP和记搜可以互相转换 显然这个题是可以用记忆化搜索过的,那我们应传哪几个参数? 首先就是记搜最基本的位置标记. 然后就是枚举的数字各位之和,以及取模之后的余数(判断能否整除某个数). 最后就是判边界的参数. 当我们搜到最后一位时如果余数为0,并且各位之和=mod,那就直接返回1,否则返回零. 显然我们把这几个数装进数组里,是开不下的. long long 为8字节 \(8\times 20\times 200\times 200\times 200 \div1

BZOJ 1799 同类分布(数位DP)

给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数.1<=a<=b<=1e18. 注意到各位数字之和最大是153.考虑枚举这个东西.那么需要统计的是[0,a-1]和[0,b]内各位数字之和为x且能整除x的数字个数. 那么我们只需要数位dp一波即可. 令dp[pos][i][x]表示有pos位且数字之和为x的数mod P=i的数字个数. 则转移方程显然可得. # include <cstdio> # include <cstring> # include

【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

[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

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 类似的分布 解读

[原标题] 1799: [Ahoi2009]self 同类分布 Time Limit: 50 Sec  Memory Limit: 64 MB Submit: 554  Solved: 194 [id=1799" style="color:blue; text-decoration:none">Submit][id=1799" style="color:blue; text-decoration:none">Status] Descr

手打AC的第2道数位DP:BZOJ1799: [Ahoi2009]self 同类分布

先讲下个人对于数位DP的看法吧... 挺难理解的 首先需要明白的一点:前缀和很重要 其次:必须用到记忆化搜索(本人蒟蒻,必须要用这种方法降低难度) 然后呢,需要判断约束的条件:(1.前缀0(有时需要,有时不需要):2.数位的取值(基本都需要)) 比如这道题,乍一看无思路,然后呢.... 就会出现很神奇的事情 大胆尝试(第一次)3维(题解本来是4维的...) 居然就XJB A了... 略显蛋疼... 回归正题*2: 本题的状态有些难找,但是由于数位最多的也只有pos,所以就可枚举所有的数位和...

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)$的动态规划解决. 接