bzoj 1799 [Ahoi2009]self 同类分布(数位DP)
Posted jasony
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1799 [Ahoi2009]self 同类分布(数位DP)相关的知识,希望对你有一定的参考价值。
题目:
解析:
设 $f[loc][js][mod]$ 为第 $loc$ 位(从左往右),各位数和为 $js$ ,当前余数为 $mod$ 的数的个数
要求 $n$ 可以被各位数和整除,也就是 $n == 0 (mod js)$
这个题,$n$ 的最大位数为18,所以各位数和最大为 $sum<=9*18=162$ ,数据较小,可以直接枚举,对每一个 $sum$ 都记忆化搜索一遍,看 $js==sum$ 时有多少数满足条件,然后累加答案
ps:因为算 $(a,b)$ ,所以要用 $(1,b)-(1,a-1)$
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 long long num[21],f[21][170][170],sum=0;//num负责统计n的每一位的值 4 long long dfs(bool xz,int loc,int js,int mod) 5 //xz 代表这一位(指loc)是否到达上限(n在loc位的值) loc,js,mod和f[][][]中的意义一致 6 { 7 if(js>sum) return 0; 8 //当累加答案超过sum,返回0 9 if(loc==0) return mod==0&&js==sum; 10 //当累加等于sum且余数为0,返回1 11 if(xz==0&&~f[loc][js][mod]) return f[loc][js][mod]; 12 //当f[][][]被查询过,直接返回 13 int u=9; 14 if(xz==1) u=num[loc]; 15 //达到上限,对下一位有限制 16 long long ans=0; 17 for(int i=0;i<=u;++i) 18 { 19 ans+=dfs(xz&&(i==u),loc-1,js+i,(mod*10+i)%sum); 20 } 21 if(xz==0) f[loc][js][mod]=ans; 22 return ans; 23 } 24 long long work(long long x) 25 { 26 int len=0; 27 while(x) 28 { 29 num[++len]=x%10; 30 x/=10; 31 } //对 num[]的预处理 32 long long ans=0; 33 for(int i=1;i<=len*9;++i) 34 { 35 memset(f,-1,sizeof(f)); 36 sum=i; 37 ans+=dfs(1,len,0,0); 38 } //枚举无需多言 39 return ans; 40 } 41 int main() 42 { 43 long long a,b; 44 cin>>a>>b; 45 cout<<work(b)-work(a-1); 46 return 0; 47 }
如果哪里出现问题或者讲的不够明白,请及时评论
以上是关于bzoj 1799 [Ahoi2009]self 同类分布(数位DP)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1799: [Ahoi2009]self 同类分布
BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin
BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin