洛谷 1025.数的划分

2024-03-09 17:36
文章标签 划分 洛谷 1025

本文主要是介绍洛谷 1025.数的划分,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这道题用的知识点是DFS+剪枝。难的不在DFS上,而是在剪枝上如何选择。

思路:这道题我们看到是按照字典序排的,但是,我们注意到,看似是全排列的递归,实则不是。

我们前面也了解过,全排列的数字大小是没有规则的,当然指数型也不可能,这并不涉及到选与不选的问题。而且,我们看到,这些数字有点像升序排列的,所以可能会是组合型递归。但是呢,我们又发现,它们的数字并不是严格单调的,而是有相同的数字在里面排序。这怎么办呢?

改进方法已经在代码里了,就是在进行下一次dfs的时候我们只需要写上i就行,而不是i+1,如果是i+1就会严格单调了。

只是这样写起来,会有数据点TLE。这是为什么呢?因为有些地方是需要剪枝的。那么这里我们怎么剪枝呢?如果你想说在求出来的和不是n的时候剪枝,那也是在全部数字枚举出来的时候才会判断的,仅仅是这样并不能完全剪枝。那该怎么办呢?这里,我们直接在循环里剪枝,也就是在枚举的过程中进行剪枝。怎么剪枝呢?举个例子:

当我们n=7,k=4时,这个时候假如我们已经列举到1,3了,现在正在第三个位置的dfs当中,这个时候按照我们的写法下一个数字肯定是3,最后一个数字也是3,这是对于自己编写的程序的理解。

我们看,如果这几个数字加起来是不是已经超过7了?也就是说,第四个位置我们根本不需要考虑了,前面已经=7了,后面再加就不行了,这里我们直接让循环不去dfs了,而是进行下一次循环。这就省了一次dfs函数的调用!那么,怎么实现这种想法呢?

我们在循环中改进循环条件就行,这和上几次的剪枝是不一样的,这里的剪枝涉及到的是对于在枚举过程中的剪枝,而不是对于全部枚举完之后的剪枝,这里是不同点。在上面的例子中,我们看到,其实知道了第三个数字我们也就知道了第四个数字了。所以,我们只需要循环到第二个位置后,判断后面两个位置的和与前面我们已经计算了的sum相加是不是<=n就行了,这就是优化的地方。

注意:这里的dfs有三个变量,第一个是位置,第二个是从哪个数开始枚举,第三个则是累加的数用来记录的。

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath> 
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<sstream>
#include<map>
#include<limits.h>
#include<set>
#define MAX 100010
#define _for(i,a,b) for(int i=a;i<(b);i++)
#define ALL(x) x.begin(),x.end()
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
int arr[MAX];
LL n, m, counts, num;
void dfs(int  u,int st,int sum) {if (u > m) {if (sum<n || sum>n)return;else {counts++;}return;}for (int i = st; sum+(m-u+1)*i <= n; i++) {arr[u] = i;dfs(u + 1,i,sum+i);arr[u] = 0;}}
int main() {ios::sync_with_stdio(false);cin.tie(NULL); cout.tie(NULL);cin >> n >> m;dfs(1,1,0);cout << counts << endl;return 0;
}

这篇关于洛谷 1025.数的划分的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/791423

相关文章

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

Thread如何划分为Warp?

1 .Thread如何划分为Warp? https://jielahou.com/code/cuda/thread-to-warp.html  Thread Index和Thread ID之间有什么关系呢?(线程架构参考这里:CUDA C++ Programming Guide (nvidia.com)open in new window) 1维的Thread Index,其Thread

高精度计算(代码加解析,洛谷p1601,p1303)除法待更新

目录 高精度加法 高精度减法 高精度乘法 高精度加法 我们知道在c++语言中任何数据类型都有一定的表示范围。当两个被加数很大时,正常加法不能得到精确解。在小学,我们做加法都采用竖式方法。那么我们也只需要按照加法进位的方式就能得到最终解。 8 5 6+ 2 5 5-------1 1 1 1 加法进位: c[i] = a[i] + b[i];if(c[i] >=

【电子通识】洁净度等级划分及等级标准

洁净度常用于评估半导体、生物制药、医疗、实验室及科研院所、新能源等领域的洁净室、无尘室或者无菌室等环境。         一般来说,晶圆光刻、制造、测试等级为100级或1000级的洁净间,百级洁净间要求空气中0.5微米的尘埃粒子数不得超过每立方米3520个;等级为1000级的洁净间要求0.5微米的尘埃粒子数不得超过每立方米35200个。         晶圆切割或封装工序一

洛谷 凸多边形划分

T282062 凸多边形的划分 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 先整一个半成品,高精度过两天复习一下补上 #include <iostream>#include <algorithm>#include <set>#include <cstring>#include <string>#include <vector>#include <map>

能量项链,洛谷

解释:  环形dp问题还是考虑将环拉直,可以参考我上一篇文章:环形石子合并 [2 3 5 10 2] 3 5 10 将环拉直,[]内是一个有效的区间,可以模拟吸收珠子的过程,         如[2 3 5] <=>(2,3)(3,5)    2是头,3是中间,5是尾 len >= 3:因为最后[2 10 2]是最小的可以合并的有效区间 len <= n + 1因为[2 3

n条直线最多能划分出多少个平面?

N条直线,两两相交,其交点各不不同,则产生的交点数目为N个数中取2个数的组合; 同时,也只有这种情况下(两两相交,也交点不同),分割的平面数最多, 数目为: 2 + (N-1)(N+2)/2.  这里求最少平面数没有意义,因为最少平面数就是N+1, 即N条直线两两平行的时候,分割的平面最少。 举例: 1条直线分割平面数最多为2; a1 = 2 2条直线分割平面数最多为4;

在不损坏数据的情况下给WIN7重新划分分区

小易接到个求助电话:我的机器上已经装好了系统,但是只有一个分区。我不想重装系统重新分区,能不能再分出一个分区?   这个故障可能是困惑很多网友的一个故障。一般,有一些第三方的软件可以实现这些功能。但是,现在在 Windows Vista/Windows 7 里允许你对现有分区大小进行一定范围的调整。   来看一下操作办法:   准备工作   这个操作必须要求你的文件系统是 N

【非零段划分 / 2】

题目 思路 第一种思路:按照表面题意,枚举p,处理数组后进行计数: 复杂度 ∈ O ( n ⋅ m ) 复杂度 \in O(n \cdot m) 复杂度∈O(n⋅m) 第二种思路:把数组看成一个二维的山形图,先将相邻的水平线段转化成点(对数组unique),再对每个子结构进行考虑 复杂度 ∈ O ( m i n ( n , m ) ) 复杂度 \in O(\;min(

洛谷P5490扫描线

0是最小的数字,将一个线段看成一个区间,对于一个矩形,从下扫到上,入边为1,而出边为-1,意思是将这个区间上的所有点加1(区间修改).把线段表示为Line[i],其中记录了l,r,h,tag,左右端点,高度,入边还是出边(1或-1) 那么每次区间修改后不为0的区间它的值可能是1,2,3或者是其它数字,这不好统计,可以将它转化一下,0是不是表示没有被覆盖过的地方,我们只要统计0的个数然后用总长减去