首页 > 其他分享 >20241030每日一题洛谷P1147

20241030每日一题洛谷P1147

时间:2024-11-02 17:01:31浏览次数:3  
标签:遍历 洛谷 int mid start 000 P1147 区间 20241030

普及-每日一题洛谷P1147

题目描述

对一个给定的正整数 \(M\),求出所有的连续的正整数段(每一段至少有两个数),这些连续的自然数段中的全部数之和为 \(M\)。

例子:\(1998+1999+2000+2001+2002 = 10000\),所以从 \(1998\) 到 \(2002\) 的一个自然数段为 \(M=10000\) 的一个解。

输入格式

包含一个整数的单独一行给出 \(M\) 的值(\(10 \le M \le 2,000,000\))。

输出格式

每行两个正整数,给出一个满足条件的连续正整数段中的第一个数和最后一个数,两数之间用一个空格隔开,所有输出行的第一个按从小到大的升序排列,对于给定的输入数据,保证至少有一个解。

样例输入

10000

样例输出

18 142 
297 328 
388 412 
1998 2002

可以采取枚举、前缀和、二分、双指针等方法

枚举+二分解出区间跨度:

思路大致如下:

  • 首先处理数据范围,减少复杂度:

    因为(\(10 \le M \le 2,000,000)\),并且每一段至少有两个数,所以能保证取到 \(M=2,000,000\) 的最小区间为\([(1,000,000),(1,000,001)]\)

  • 意思就是说我们只需要从 \(0\) 遍历到 \(M/2\),对每次遍历都做一次二分搜索,没有搜索到匹配的区间跨度则退出继续遍历

  • 当某一次遍历找到了匹配的区间跨度使得区间和为 \(M\) 时,输出当前遍历的左区间和二分找到的右区间

  • 直到遍历结束,退出程序

具体实现如下:

find函数,寻找匹配的区间跨度

int find(int start) {
	int l = 1, r = n;
	while (l<r)
	{
		long long mid = l + r >> 1;//long long 防止求和数据溢出
		if ((start + mid + start) * (mid + 1) / 2 == n)//等差数列求和公式,二分结果可能过大
			return mid;
		else if ((start + mid + start) * (mid + 1) / 2 > n)
			r = mid;
		else
			l = mid + 1;
	}
	return 0;//未找到匹配的区间跨度返回0
}

从 \(1\) 开始遍历到 \(M/2\):

for (int i = 1; i <= m / 2; i++) {
	if (find(i) == 0) continue;//未找到匹配的区间跨度则继续遍历i
	else printf("%d %d\n", i, i + find(i));//输出匹配的区间跨度
}

完整代码:

int m;

int find(int start) {
	int l = 1, r = m;
	while (l<r)
	{
		long long mid = l + r >> 1;
		if ((start + mid + start) * (mid + 1) / 2 == m)
			return mid;
		else if ((start + mid + start) * (mid + 1) / 2 > m)
			r = mid;
		else
			l = mid + 1;
	}
	return 0;
}

int main()
{
	scanf("%d", &m);
	for (int i = 1; i <= m / 2; i++) {
		if (find(i) == 0) continue;
		else printf("%d %d\n", i, i + find(i));
	}
	return 0;
}

枚举+前缀和找到区间:

思路如下:

  • 存储前缀和到数组中,同理只需要存到第 \(1,000,000\) 项
  • 遍历右区间,在存在右区间的前提下,往回检索左区间,存在匹配的左右区间,直接输出
  • 因为每次遍历左区间时,区间和总是随左区间减小而增大的,如果遍历到的左区间使区间和大于 \(M\),则直接退出
  • 若遍历完左区间,未能找到匹配值,则继续遍历右区间

记录前缀和:

for (int i = 1; i <= 1000000; i++) 
	sum[i] += sum[i - 1] + i;

遍历右左区间:

for (int i = 1; i <= m / 2 + 1; i++) {//先遍历右区间
	for (int j = i; j >= 1; j--) {//往回检索左区间
		if (sum[i] - sum[j - 1] > m) break;//区间和大于M直接退出
		if (sum[i] - sum[j - 1] == m && j != i) printf("%d %d\n", j, i);
	}
}

完整代码:

int m,sum[1000010];

int main()
{
	scanf("%d", &m);
	for (int i = 1; i <= 1000000; i++) 
		sum[i] += sum[i - 1] + i;
	for (int i = 1; i <= m / 2 + 1; i++) {
		for (int j = i; j >= 1; j--) {
			if (sum[i] - sum[j - 1] > m) break;
			if (sum[i] - sum[j - 1] == m && j != i) printf("%d %d\n", j, i);
		}
	}
	return 0;
}

标签:遍历,洛谷,int,mid,start,000,P1147,区间,20241030
From: https://www.cnblogs.com/dianman/p/18522180

相关文章

  • 20241029每日一题洛谷P1024
    普及-每日一题洛谷P1024有形如:\(ax^3+bx^2+cx+d=0\)这样的一个一元三次方程。给出该方程中各项的系数(\(a,b,c,d\)均为实数),并约定该方程存在三个不同实根(根的范围在\(-100\)至\(100\)之间),且根与根之差的绝对值\(\ge1\)。要求由小到大依次在同一行输出这三个实......
  • OIFC未来共同体20241030noip模拟四
    T1我们发现\(1\)其实根本没有用,只和一个连通块里的\(0\)的个数有关,直接\(dfs\),判断即可。#include<iostream>#include<cstring>usingnamespacestd;inlineintread(){registerintx=0,f=1;registercharc=getchar();while(c<'0'||c>'......
  • 20241030 训练记录
    [TJOI2012]桥删边最短路模板。只需求出对于每条边,不经过这条边的最短路就做完了。考虑不在原\(1\)到\(n\)最短路上的边,它们的答案就为原本的最短路。对于原本就在最短路上的边,既然删掉了这条边,那么新的最短路一定会经过另外一条边,设这条边为\((u,v,w)\),\(dis(u,v)\)表......
  • 整数二分 ——洛谷p9240冶炼金属
    #include<bits/stdc++.h>#defineendl'\n'#defineINF0x3f3f3f3f#defineintlonglongusingnamespacestd;constintN=1e4+10;inta[N],b[N];intn;//找左节点boolcheck_min(intmid){ for(inti=0;i<n;i++) { if(b[i]<a[i]/mid) return......
  • 洛谷题单指南-字符串-P3369 【模板】普通平衡树
    原题链接:https://www.luogu.com.cn/problem/P3369题意解读:平衡树的基本操作,模版题。解题思路:1、二叉搜索树-BST二叉搜索树满足这样的性质:每一个节点的权值大于它的左儿子,小于它的右儿子。对BST进行中序遍历,将得到一个从小到大的有序序列,因此BST是为了维护一个有序序列的动态......
  • 题解 洛谷 Luogu P1308 [NOIP2011 普及组] 统计单词数 C++
    题目传送门:P1308[NOIP2011普及组]统计单词数-洛谷|计算机科学教育新生态https://www.luogu.com.cn/problem/P1308getline() 会清除使当次getline() 终止的换行,而cin 不会因此cin 以换行终止,之后还需要getline()的话,需要用getchar() 吞换行Linux的一些相......
  • 洛谷 P2606 [ZJOI2010] 排列计数 题解
    题目链接[ZJOI2010]排列计数-洛谷题解看到\(p_i>p_{\lfloori/2\rfloor}\)这个条件,可能一开始不会有什么想法。但是如果我们换种写法,即:\(p_i<p_{2i}\landp_i<p_{2i+1}\)。这样我们就能很容易看出来,这是小根堆的形式。现在我们从根节点开始考虑,假设左子树的大小......
  • 洛谷B2064
    B2064斐波那契数列-洛谷|计算机科学教育新生态斐波那契数列题目描述斐波那契数列是指这样的数列:数列的第一个和第二个数都为$1$,接下来每个数都等于前面$2$个数之和。给出一个正整数$a$,要求斐波那契数列中第$a$个数是多少。输入格式第1行是测试数据的组数n,后面......
  • 洛谷Python顺序结构题解合集
    P5705【深基2.例7】数字反转a=s[0]b=s[1]c=s[2]d=s[4]print(f"{d}.{c}{b}{a}")P5706【深基2.例8】再分肥宅水ans=float(a[0])/int(a[1])beizi=2*int(a[1])print(f"{ans:.3f}\n{beizi}")P5708【深基2.习2】三角形面积p=0.5*(a+b+c)ans=pow((p*(p-a)*(p-b)*(p-c)),0.5......
  • POI2011/洛谷P3523 DYN-Dynamite
    前言Link本来一个很直观的题面,非要搞形式化题意反而使题意变得非常迷惑。题意有一栋树形建筑,其中有一些点摆放了TNT,树边上都摆放了引信,引信的燃烧时间为\(1\)秒\(/\)边,现在你要选择\(m\)个点同时点燃引信(起爆),则显然TNT被引爆的时间为到离它最近的起爆处的距离,请你求......