首页 > 其他分享 >数位dp

数位dp

时间:2024-05-19 20:41:38浏览次数:16  
标签:cnt ch last int windy dp 数位

一、算法简析

数位dp题目的特点

求某个区间 \([L,R]\) 内,满足某种性质的数的个数。

数位dp的解题技巧

技巧一

类似前缀和,转换为 \([0,R]-[0,L-1]\) 求解。分别统计两个区间内满足条件的数的个数,再作差。

技巧二

由于边界 \(R\) 的限制,首先就要保证讨论的数小于等于 \(R\),再考虑是否满足题目要求的性质。

将边界数字 \(R\) 按数位拆分,各位数字为 \(a_i\),共 \(n\) 位。\(R=a_na_{n-1}...a_1\)。
从高位到低位填数,对于第 \(i\) 位,边界 \(R\) 在该位为 \(a_i\),分类讨论:

  • 若填 \([0,a_i-1]\),后面每一位可以随意填 \([0,9]\) 中的数字,都保证小于 \(R\)。
  • 若填 \(a_i\),则将该位固定为 \(a_i\),接着讨论 \(i-1\) 位。

按照这个方法讨论数,可以保证不大于 \(R\)。

相关题目

P2657 [SCOI2009] windy 数

P2657 [SCOI2009] windy 数

题目分析

令 \(f[i][j]=\) 一共有 \(i\) 位,首位数字为 \(j\) 的windy数的个数

预统计

根据windy数的性质:不含前导零且相邻两个数字之差至少为 2 的正整数,得到转移方程

\[f[i][j]=\begin{cases} \sum_{k=0}^9{f[i-1][k]}&,~~~~i\in[2,n]~and~j\in[0,9]~and~|k-j|\ge2\\ 1&,i==1~and~j\in[0,9] \end{cases} \]

虽然windy数要求不含前导零,但在预统计时,\(j\) 可以为取 \(0\)。因为预统计是从低位向高位填数,此时首位为 \(0\)的情况,会对再高一位非零情况做出贡献。例:\(dp[5][2]\) 需要包含 \(dp[4][0]\)。因此,我们也需要统计 \(f[i][0]\) 的情况。

在根据边界 \(R\) 统计个数时,忽略前导零的情况即可。

开始统计

对于 \([0,R]\) 的windy数,我们分成两部分讨论:

  • 位数为 \(n\) 的数,按上文提到的技巧二,从高位向低位讨论,注意不存在前导零。
  • 位数小于 \(n\) 的数,直接累加 \(dp[i][j],~i\in[1,n-1]~and~j\in[1,9]\)。

注意,0 不是windy数

Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

ll quickin(void)
{
	ll ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

const int MAX = 12;
int A[MAX], f[MAX][MAX];

// 初始化,预统计windy数 
void init(void)
{
	for (int i = 0; i <= 9; ++i)    f[1][i] = 1;
	
	for (int i = 2; i < MAX; ++i)
		for (int j = 0; j <= 9; ++j) // 此处j可以为0,因为非首位数字可以为0 
			for (int k = 0; k <= 9; ++k)
				if (abs(k - j) >= 2)    f[i][j] += f[i - 1][k];
}

int dp(int x)
{
	if (!x)     return 0; // 不含前导0
	
	int cnt = 0;
	while (x)
	{
		A[++cnt] = x % 10;
		x /= 10;
	}
	
	int ans = 0, last = -2; // last=-2保证i=cnt,j=1时,也满足if条件 
	
	// 位数等于cnt 
	for (int i = cnt; i >= 1; --i)
	{
		int now = A[i];
		for (int j = (i == cnt); j < now; ++j) // 前导数字不为0,其它位可为0 
			if (abs(j - last) >= 2)    ans += f[i][j];
			
		if (abs(now - last) < 2)    break;
		last = now;
		if (i == 1)    ans += 1; // 特判,即x是否满足 
	}
	
	// 位数小于cnt
	for (int i = 1; i < cnt; ++i)
		for (int j = 1; j <= 9; ++j)
			ans += f[i][j]; 
	
	return ans;
}

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	init();
	
	int a, b;
	a = quickin(), b = quickin();
	cout << dp(b) - dp(a - 1) << endl;
	
	return 0;
}

标签:cnt,ch,last,int,windy,dp,数位
From: https://www.cnblogs.com/hoyd/p/18200724

相关文章

  • DDPM原理
    生成模型核心原理解释:将观测变量(数据集图片)进行编码为具有某个确定分布(一般为正太分布)的隐变量,然后再将该隐变量解码为观测变量。在推理过程中就可以通过在隐变量的分布中进行随机采样,然后将其解码为生成的图片,进而实现生成内容的多样性。DDPMDDPM相比VAE,在将观测变量编码为......
  • EDP .Net开发框架--业务模型
    平台下载地址:https://gitee.com/alwaysinsist/edp业务模型概述业务模型管理中所涉及的业务模型,业务模型的属性,业务模型的视图都是可以通过权限设置来实现数据的行(视图),列(属性)权限管控。业务模型是整个EDP平台的核心基础,数据的查询、新增、修改、删除、行列权限都是通过业务模型......
  • m基于BP译码算法的LDPC编译码matlab误码率仿真,对比不同的码长
    1.算法仿真效果matlab2022a仿真结果如下:   2.算法涉及理论知识概要       低密度奇偶校验码(Low-DensityParity-Check,LDPC)是一种高效的前向纠错码,因其优越的纠错性能和近似香农限的接近程度而广泛应用于现代通信系统中。LDPC码的编译码算法众多,其中BeliefProp......
  • C# SoundPlayer播放资源文件中嵌入的.wav文件
    usingSystem.IO;usingSystem.Media;usingSystem.Windows.Forms;usingNamespce.Properties;publicstaticclassSpeakerStream{staticStreampass=Resources.pass;staticStreamfail=Resources.fail;staticbyte[]passbyte=null;stati......
  • SOSdp
    从子集和问题到and卷积枚举子集:\(O(3^{n})\) intu=15; for(ints=u;s;s=(s-1)&u){ b=s; cout<<b<<endl;}/*111111101101110010111010100110000111011001010100001100100001*/子集和问题参考好的博客https://ottffyzy.github.io/algos/dp/s......
  • 概率dp
    概率dp首先是正着递推的计算概率的dp问题https://ac.nowcoder.com/acm/contest/28263/A纯数学题对随机的数字大小分类讨论,计算概率的时候利用高中几何概型的线性规划手法进行计算。doubleg=0.5;voidsolve(){ doublek,x;cin>>k>>x; doubleans=0; if(k==x)ans=g; else......
  • [动态规划] 区间 dp
    区间dp石子合并将区间长度\(len\)作为\(dp\)的阶段设\(f[l][r]\)表示把最初的第\(l\)堆到第\(r\)堆石子合并成一堆,需要消耗的最少体力。合并代价就是这两堆石子的质量和,这里可以用前缀和直接计算,设\(s[i]\)表示前\(i\)堆石子的质量和。状态转移方程:\[f[l][r]......
  • WordPress古腾堡编辑器和经典编辑器详细对比,哪个好用?
    WordPress古腾堡编辑器(GutenbergEditor)是WordPress5.0版本引入的默认编辑器,取代了之前的经典编辑器。古腾堡编辑器的设计理念是基于“块”(blocks),让用户能够更直观、灵活地编辑内容。WordPress经典编辑器是WordPress5.0版本之前的默认编辑器,它采用传统的单个文本框界面,用户可以......
  • C122 李超树合并+DP CF932F Escape Through Leaf
    视频链接:C122李超树合并+DPCF932FEscapeThroughLeaf_哔哩哔哩_bilibili   C65【模板】线段树合并P4556[Vani有约会]雨天的尾巴-董晓-博客园(cnblogs.com)CF932FEscapeThroughLeaf#include<iostream>#include<cstring>#include<algorithm>using......
  • 线头 DP 问题
    引入对于一种需要通过相邻两项来维护的一些DP问题,通常的DP会无法转移。这时便要使用线头DP。这种DP又名连续段DP,其关键在于维护已近满足条件的不同连续段的贡献总和。线头DP本质上只是一种转移状态,这种状态能与排列成双射的同时,还能只考虑两端的性质来使状态便于记录......