构造题作为常见题型,要求解题者通过观察问题结构规律,寻找通用方法以应对规模变化。解题时,需从多方面思考,如关注规模增长影响、推广规律、考虑状态转移、识别模式,需要大量练习及留意特殊情况。
构造题具有两大显著特点:一是高自由度,虽构造方式多样且有简易解法,但易致考生思路迷茫;二是形式灵活多样,不存在通用解法与共性思路,对考生观察与归纳能力要求高。
针对构造题,可采用多种解题方法,包括仔细分析题目各要素、尝试特例与极端情况找解法规律、寻找模式规律并推广、逆向构造、用数学归纳法证明、灵活运用多学科知识、反复实践总结经验以及保持耐心与信心。
在应用场景方面,构造题广泛涉及数学、图论、字符串处理、组合排列、游戏策略、逻辑推理、数据结构、动态规划、贪心算法及模拟问题等领域,通过不同场景考查选手能力。
(一)
蓝桥小蓝喜欢数学,他特别喜欢做数学题,有一天他遇到了一个有趣的数学题:
x/1+y/1+z/1=N/1
现在给定一个正整数N,小蓝想知道当x、y、z取何值时,上述等式成立。
请你帮助小蓝找到满足条件的整数x、y、z。
输入:
输入包含一个正整数N(1 ≤ N ≤ 1000)。
输出:
如果存在满足条件的整数x、y、z,则输出一个满足条件的解,以空格分隔。如果有多组解,请输出任意一组即可。
如果不存在满足条件的解,则输出"No Solution"。
样例
当N = 1时,选择x = 2, y = 3, z = 6: 1/2 + 1/3 + 1/6 = 1,满足条件。
当N = 2时,选择x = 4, y = 6, z = 12: 1/4 + 1/6 + 1/12 = 1/2,满足条件。
当N = 3时,选择x = 7, y = 10, z = 70: 1/7 + 1/10 + 1/70 = 1/3,满足条件。
当N = 4时,选择x = 5, y = 8, z = 40: 1/5 + 1/8 + 1/40 = 1/4,满足条件。
x/1+y/1+z/1=N/1,这个题如果数学题做的多的话,我们能够很快想到:
当N=2时,1/2=1/4+1/4,1/4=3/12=1/12+2/12=1/12+1/6,所以x=4 y=6 z=12
当N=3时,1/3=1/6+1/6,1/6=3/18=1/18+2/18=1/18+1/9,所以x=6 y=9 z=18
这里的答案就跟样例不同了,因为是构造体,答案比较开放,题目的样例是随机出现,一般出题人可能会用一些比较偏的数据误导做题人。
当N=4时,1/4=1/8+1/8,1/8=1/12+1/24,所以x=8 y=12 z=24
显然我们可以推导得到,当N=n时,x=2n y=3n z=6n为原式的一组解。
这个题目可以归类于数学题目,我们只需要构造出一组满足某个式子的解。
n = int(input()) x = 2 * n y = 3 * n z = 6 * n print(x,y,z)
(二 )
【题目描述】数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一部分的数列,只记得其中N个整数。现在给出这N个整数,小明想知道包含这N个整数的最短的等差数列有几项,请输出这几项。
【输入描述】输入的第一行包含一个整数N。第二行包含N个整数A₁,A₂,…,Aₙ。(注意A₁~Aₙ并不一定是按等差数列中的顺序给出)(对于所有评测用例,2≤N≤100000,0≤Ai≤10⁹。)
【输出描述】输出一个序列表示答案
所有数字间距离最小的间隔是公差吗?
等差数列的最小间隔(实际上不是公差),例如{2,5,7},最小的间隔是2,但公差不是2,是1。
这其实一个GCD构造问题,可以通过计算给定数字间的所有间隔的最大公约数(GCD)来确定。把n个数据排序,计算它们的间隔,对所有间隔做GCD,结果为公差。
同时,通过最小值、最大值和公差,可以计算出等差数列的最少数量。
最少数量等于 =(最大值-最小值)/公差+1。
从最小值到最大值依次输出即可。
import math n = int(input()) nums = sorted(map(int, input().split())) diffs = [nums[i + 1] - nums[i] for i in range(n - 1)] # 所有相邻元素的差 # 计算最大公约数 d = diffs[0] for num in diffs[1:]: d = math.gcd(d, num) mn, mx = nums[0], nums[-1] # 等差数列的最小值和最大值 seq = [mn + i * d for i in range((mx - mn) // d + 1)] print(' '.join(map(str, seq)))
(三)
题目描述: 给定一个正整数N,你需要构造一个包含N个节点的简单连通图。节点编号从1到N。同时,设任意边的两个节点的编号为a,b。a,b需要满足:(a&1)Xor(b&1)=1。每条边的权值为边所连接的两个节点的编号和,使得的最长边和最短边之间的差值小于等于3。
输入描述:
输入包含一个正整数N (2 ≤ N ≤ 1000)。
输出描述:
先输出一个M表示总共M条连边。
然后输出包含M行,每行包含两个整数,表示图中一条边的两个节点编号。
我们先剖析一下含义: (a&1)Xor(b&1)=1
a&1判断最后一个二进制位是不是1,如果为1则为1,如果为0则为0。 显然为0时为偶数,为1时为奇数。
两个数的奇偶性做亦或等于1,那么也就是说a和b不能同时为奇数或者同时为偶数。 即a和b一个为奇数另一个为偶数。
回归题目也就是说一条边两个节点的需要一个为偶数一个为奇数。
每条边的权值为边所连接的两个节点的编号和,使得的最长边和最短边之间的差值小于等于3。
这里就比较开放了,连边的方式有很多种,既然是小于等于某个数,那我们让他们最小就好了,或者说不连最小了,没有边按目前的信息是符合题意。
显然出题人早就想到了这一点,不会让我们偷懒钻空子。你需要构造一个包含N个节点的简单连通图。
我们虽然不能一个边不连,但是最少的连通图,我们知道是树,最少连N-1边,遵循着少连接少出错的原则,我们就构建一个树即可。
结论是构建一个棵只由奇偶连边的树,使得最长边和最短边的权值不超过3。
既然不让超过3,我们使得连边的权值最小即可,因为最小肯定符合题意(如果有的话),因为最小不符合题意,那么此题无解,因为求的是不超过3。最小超过了3那其他的肯定超过3。
最小的话就是,让最大值最小,让最小值最大。
假设N为偶数的话,那就1连N,3连N-2...此时所有边的值都是N+1。
如果N为奇数怎么办?那就是在添加一个N+1的节点呗。直接挂到1上即可,如果求最优解的话其实是这样一个结构。
奇数情况下不输出划圈的连线
def print_graph_connections(n): print(n-1) if n % 2 == 0: # 偶 for i in range(1, n + 1, 2): print(i, n - i + 1) for i in range(1, n - 1, 2): print(i, n - i - 1) else: # 奇 for i in range(3, n + 1, 2): # 跳过最大点 print(i, n - i + 2) for i in range(1, n - 1, 2): print(i, n - i) n = int(input("请输入节点数n: ")) print_graph_connections(n)
(四)
给定一个正整数n(n>0)。找到任何一个满足以下条件的整数s,或者报告没有这样的数字:
在s的十进制表示中:
s>0
s由n位数字组成
s中没有任何数字等于0
s不能被它的任何一个数字整除
输入包含多个测试用例。 输入的第一行包含一个整数t(1≤t≤400),表示测试用例的数量。 接下来的t行描述了每个测试用例。 每个测试用例包含一个正整数n(1≤n≤10^5)。 保证所有测试用例中n的总和不超过10^5。
首先,我们将最后一位数字设置为3。
然后,我们将前面的位数都设置为2,这样可以确保数不会被最后一位的3整除,由于最后一位是3不是偶数所以也没办法被2整除。
接着,我们检查前面的位数,如果前面的位数的数量是3的倍数(一个简单的知识如果个位数的和能够被3整除那么这个数也能被3整除),此时那么我们可以将第一位的2替换为一个素数(比如5或7),这样就可以确保数不会被整除,同时也满足了题目的条件
t = int(input()) for _ in range(t): n = int(input()) if n == 1: print(-1) else: s = '2' * (n - 1) + '3' if (n - 1) % 3 == 0: s = '5' + s[1:] print(s)