首页 > 其他分享 >DP

DP

时间:2024-08-03 18:39:00浏览次数:5  
标签:10 int ll mi ans DP

1)
数位DP

数位 DP:用来解决一类特定问题,这种问题比较好辨认,一般具有这几个特征:

要求统计满足一定条件的数的数量(即,最终目的为计数);

这些条件经过转化后可以使用「数位」的思想去理解和判断;

输入会提供一个数字区间(有时也只提供上界)来作为统计的限制;

上界很大(比如 10^{18}),暴力枚举验证会超时。

数位 DP 的基本原理:

考虑人类计数的方式,最朴素的计数就是从小到大开始依次加一。但我们发现对于位数比较多的数,这样的过程中有许多重复的部分。例如,从 7000 数到 7999、从 8000 数到 8999、和从 9000 数到 9999 的过程非常相似,它们都是后三位从 000 变到 999,不一样的地方只有千位这一位,所以我们可以把这些过程归并起来,将这些过程中产生的计数答案也都存在一个通用的数组里。此数组根据题目具体要求设置状态,用递推或 DP 的方式进行状态转移。

数位 DP 中通常会利用常规计数问题技巧,比如把一个区间内的答案拆成两部分相减(即 \mathit{ans}{[l, r]} = \mathit{ans}-\mathit{ans}_{[0, l - 1]})

那么有了通用答案数组,接下来就是统计答案。统计答案可以选择记忆化搜索,也可以选择循环迭代递推。为了不重不漏地统计所有不超过上限的答案,要从高到低枚举每一位,再考虑每一位都可以填哪些数字,最后利用通用答案数组统计答案。

例子 Luogu P2602 数字计数
代码:

点击查看代码 ``` #include using namespace std; const int N = 15; typedef long long ll; ll l, r, dp[N], mi[N]; //dp:将i位填满出现的任意一个数字的次数(不排除前导0 //mi:10的i次幂 ll ans1[N], ans2[N]; int a[N];

void solve(ll n, ll *ans) {
ll tmp = n;
int len = 0;
while (n) a[++len] = n % 10, n /= 10;
//将n拆分成每一位
for (int i = len; i >= 1; --i) {//从头到尾枚举
for (int j = 0; j < 10; j++) ans[j] += dp[i - 1] * a[i];
//对于没有顶到a[i]的数字,加上末几位的数字可能数
for (int j = 0; j < a[i]; j++) ans[j] += mi[i - 1];
// 还没有顶到i的后几位情况
tmp -= mi[i - 1] * a[i], ans[a[i]] += tmp + 1;
//对于顶到i的情况
ans[0] -= mi[i - 1];
//剔除前导0
}
}

int main() {
scanf("%lld%lld", &l, &r);
mi[0] = 1ll;
for (int i = 1; i <= 13; ++i) {
dp[i] = dp[i - 1] * 10 + mi[i - 1];
mi[i] = 10ll * mi[i - 1];
}
solve(r, ans1), solve(l - 1, ans2);
for (int i = 0; i < 10; ++i) printf("%lld ", ans1[i] - ans2[i]);
return 0;
}

</details>
特点:对于每一位从0—9进行枚举,中间对于进位特殊考虑。


未完待续...

标签:10,int,ll,mi,ans,DP
From: https://www.cnblogs.com/Euan99/p/18340895

相关文章

  • centos7上dpdk绑定vfio-pci失败
    记一次使用dpdk中的报错:运行dpdk/usertools/dpdk-devbind.py-bvfio-pci02:05.0来绑定设备到vfio-pci时,报出了如下错误:Error:bindfailedfor0000:02:05.0-Cannotbindtodrivervfio-pci:[Errno19]NosuchdeviceError:unbindfailedfor0000:02:05.0-Cannot......
  • Luogu P5005 中国象棋 - 摆上马 / Luogu P8756 国际象棋 题解 [ 蓝 ] [ 状压 dp ] [
    国际象棋:模板棋盘状压。摆上马:需要点思维的棋盘状压,相比上一道题加了“蹩马脚”的设定。Easy_version:国际象棋概述一下此类棋盘问题的思路:用二进制数表示出棋盘上某一行的状态。用位运算预处理出合法的单行状态,以及需要用到的一些东西。用位运算判断前一行或者前几行能否......
  • Debian系包管理工具dpkg,apt-get,apt的区别
    解密Linux包管理:apt和apt-get的区别-系统极客(sysgeek.cn)dpkg:幕后英雄dpkg是Debian包管理系统的核心,是一个底层工具,用于直接操作.deb文件。你可以把它想象成一个搬运工,负责把软件包里的「内容」搬到电脑里。但是,它不处理依赖关系,这项工作交由apt或apt-get来完成。ap......
  • wordpress站点转移
    title:wordpress站点转移date:2024/7/1311:11:11tag:linux学习categories:wordpress建设description:搭建后的优化top_img:https://cdn.jsdelivr.net/gh/xiaowang872/blogimage@main/images/QQ%E6%88%AA%E5%9B%BE20240713105724.pngcover:https://cdn.jsdelivr.net/......
  • Luogu P3959 宝藏 题解 [ 紫 ] [ 状压 dp ] [ 二项式定理 ]
    宝藏:一个对着蓝书代码调都能调两个小时的大毒瘤,但是思路还是很值得借鉴的,有普通状压和三进制状压两种做法,或者暴搜剪枝也可以(这里不介绍暴搜剪枝做法)。普通状压做法观察到\(n\le12\),首先想到状压。但考虑到普通的状压不太行,因为\(K\)这个数算在代价里,会导致这个dp有后效......
  • C# .NET ThreadPool 实现概述及
    微信公众平台(qq.com) 在.NET中,ThreadPool(线程池)是一个用于管理和优化线程使用的强大工具。线程池允许开发者在需要时创建线程,执行任务,并在任务完成后回收线程,从而避免了线程的频繁创建和销毁所带来的开销。ThreadPool是.NETFramework和.NETCore中并发编程的核心部分,广泛应......
  • P1006 [NOIP2008 提高组] 传纸条(线性 dp)
    link真的,第一次听懂了闫氏dp分析法,从集合的角度分析首先,两条路径,很朴素的状态表示就是定义\(f[x_1,y_1,x_2,y_2]\)来表示两条路径分别走到当前点的最大值但是,这样状态数量就达到了6.25e7,有点极限tip:动态规划的时间复杂度一般可以表示为状态数量与状态计算量的乘积注意......
  • profibus DP 使用半双工的485物理层为什么可以支持多个主站
    profibusDP使用半双工的485物理层为什么可以支持多个主站 PROFIBUSDP(DecentralizedPeripherals)是一个用于工业自动化的高速现场总线协议,广泛用于连接各种设备如传感器、执行器和控制器。PROFIBUSDP使用了RS-485物理层来实现数据传输。RS-485是一......
  • android 音频播放器,(一)SoundPool音频播放实例
    1.Apk内,预定义按键与触发按键:layout按键定义:  <Button    android:id="@+id/start"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:textAllCaps="false"    an......
  • HT-018 Div3 能量消耗 题解 [ 绿 ] [ 线性 dp ] [ 前缀和优化 ]
    能量消耗:一个前缀和优化dp的大典题,要是数据水一点\(O(n^3)\)都能硬草过去。思路显然,定义\(dp[i]\)为考虑前\(i\)个塔,并且将前面的精灵全部收集的最小代价。于是转移:\[dp[i]=min(dp[i],dp[j]+w(j,i)+c[i])\]其中\(0\lej<i\lem\),\(w(j,i)\)表示收集从塔\(j\)到......