数位DP

感觉数位 DP 一般都能一眼看出来,而且代码长得也差不多诶!

dfs 式数位 DP 模板

ll dfs(ll len,bool Limit,bool zero,ll …… ) // 其他各种条件
{
	 if(len>w) return zero^1;  // 注意!!!特判 0
	 if(!Limit && dp[len][……]!=-1) return dp[len][……];
	 ll ret=0;
	 for(ll i=0;i<=9;i++)
	 {
	 	 if(Limit && i>num[len]) break; // 只有在有 Limit 最高位限制是才需要判断是否高于最高位
	 	 if(……) // 根据题目满足各种条件
	 }
	 if(!Limit && !zero) dp[len][……]=ret; // 必须同时满足没有最高位与前导 0 限制
	 return ret;
}

ll solve(ll x)
{
	 memset(dp,-1,sizeof(dp)); // 有时要每一次都赋值!!!
	 ll w=0,tmp=x;
	 while(tmp) num[++w]=tmp%10,tmp/=10; // 统计位数
   	 // 有的情况下应在这里给 dp 数组赋值
	 return dfs(w,1,1,……);
}

memset(dp,-1,sizeof(dp)); // 有时只用赋值一次!!!

例题

几个模板题:P2657 [SCOI2009] windy 数P3413 SAC#1 - 萌数P4127 [AHOI2009]同类分布CF914C Travelling Salesman and Special NumbersP2602 [ZJOI2010]数字计数

P4317 花神的数论题

统计 \(n\) 以内正整数的二进制中 \(1\) 的个数之积。

枚举 \(k=1\dots \log_2^n\) ,分别计算二进制中 \(1\) 的个数为 \(k\) 时的数的个数,最后相乘即可。

CF288E Polo the Penguin and Lucky Numbers

一道还比较难写的数位 DP。

数位 DP 没话说,我们按照每一位向下,考虑将贡献分开来计算。

假设两个数为 \(4\times 10^p+x\)\(4\times 10^p+x+1\)(将首位 \(47\) 交错的情况单独考虑),可以先计算首位的贡献,再算其他的贡献。

那么两数之积为:\(16\times 10^{2p}+4\times 10^p\times (x+x+1)+x(x+1)\)

  • 第一项可以计算出项数,直接算出;
  • 第二项算出所有少去这一位的数的和的两倍减去两端,乘上首位。
  • 最后一项递归为子问题。

那么直接套上数位 DP 就完成啦?我们需要记录的内容有:数的个数、数的和、答案。

posted @ 2021-07-27 18:16  EricQian06  阅读(44)  评论(0编辑  收藏  举报