NOI Online能力测试 提高组题目
解析和代码由杭州二中信奥队提供
序列
【题目描述】
小 D 有一个长度为 n 的整数序列 ai(下标从 1 开始编号,下同),她想通过若干次操作把它变成序列 bi。
小 D 有 m种可选的操作,第 i 种操作可使用三元组 (ti,ui,vi) 描述:若 ti=1,则她可以使 aui 与 avi 都加一或都减一;若 ti=2,则她可以使 aui-1、avi+1,或是 aui+1、avi-1,因此当 ui=vi 时,这种操作相当于没有操作。
小 D 可以以任意顺序执行操作,且每种操作都可进行无限次。现在给定序列与所有操作,请你帮她判断是否存在一种方案能将 ai 变为 bi。题目保证两个序列长度都为 n。若方案存在请输出 YES
,否则输出 NO
。
【输入格式】
从 sequence.in 读入数据。
本题输入文件包含多组数据。
第一行一个正整数 T 表示数据组数。对于每组数据:
第一行两个整数 n,m,表示序列长度与操作种数。
第二行 n 个整数表示序列 ai。
第三行 n 个整数表示序列 bi。
接下来 m 行每行三个整数 ti,ui,vi,第 i 行描述操作 i。
注意:同一个三元组 (ti,ui,vi) 可能在输入中出现多次。
【输出格式】
输出到文件 sequence.out 中。
对于每组数据输出一行一个字符串 YES
或 NO
表示答案。
【样例1输入】
3
1 1
1
3
1 1 1
2 3
1 2
4 5
1 1 2
2 1 2
1 1 2
3 3
1 2 3
5 5 4
1 1 2
1 1 3
2 2 3
【样例1输出】
YES
YES
YES
【样例1解释】
第一组数据:使用一次操作 1。第二组数据:使用三次操作 1。第三组数据:使用三次操作 1,令 a1,a2 都增加 3,再使用一次操作 2,令 a1,a3 都增加 1。
【数据范围与提示】
对于测试点 1 - 5:n=2,m=1,ai,bi ≤ 99,u1 ≠ v1,t1=1。
对于测试点 6 - 10:n=2,m=1,ai,bi ≤ 99,u1 ≠ v1,t1=2。
对于测试点 11 - 12:n=2,ai,bi ≤ 99,ui ≠ vi。
对于测试点 13 - 16:ti=2。
对于测试点 17:n,m ≤ 20。
对于测试点 18:n,m ≤ 1000。
对于所有测试点:1 ≤ T ≤ 10,1 ≤ n,m ≤ 105,1 ≤ ai,bi ≤ 109,ti ∈ {1,2},1≤ ui,vi≤ n。
【时间限制】
2.0s
【空间限制】
256MB
【上传文件】
上传c, cpp或pas语言源程序,文件名应依次为sequence.c, sequence.cpp, sequence.pas。
【解析】
我们令vali =ai - bi;,显然只需要对val数组进行操作,使它变成全0即呵。
把第二种操作提取出来,在ui和vi之间连一边,在某个联通块内如果val的和等于0,就可以构造出一组使这个联通块变为全0的方案。我们将其缩点,就变成了没有二操作的情况,这个时候考虑一个联通块是不是二分图,如果是二分图, 只需要判断二分图两边的val之和是否相等,否则判断val之和的奇偶性。构造方案留作思考。
【代码】
冒泡排序
【题目描述】
给定一个 1 ~ n 的排列 pi,接下来有 m 次操作,操作共两种:
- 交换操作:给定 x,将当前排列中的第 x 个数与第 x+1 个数交换位置。
- 询问操作:给定 k,请你求出当前排列经过 k 轮冒泡排序后的逆序对个数。
对一个长度为 n 的排列 pi 进行一轮冒泡排序的伪代码如下:
for i = 1 to n-1 :
if p[i] > p[i + 1] :
swap(p[i], p[i + 1])
【输入格式】
从文件 bubble.in 中读入数据。
第一行两个整数 n,m,表示排列长度与操作个数。
第二行 n 个整数表示排列 pi。
接下来 m 行每行两个整数 ti,ci,描述一次操作:若 ti=1,则本次操作是交换操作,x=ci;若 ti=2,则本次操作是询问操作,k=ci。
【输出格式】
输出到文件 bubble.out 中。
对于每次询问操作输出一行一个整数表示答案。
【样例1输入】
3 6
1 2 3
2 0
1 1
1 2
2 0
2 1
2 2
【样例1输出】
0
2
1
0
【样例1解释】
第一次操作:排列为 {1,2,3},经过 0 轮冒泡排序后为 {1,2,3},0 个逆序对。
第二次操作:排列变为 {2,1,3}。
第三次操作:排列变为 {2,3,1}。
第四次操作:经过 0 轮冒泡排序后排列变为 {2,3,1},2 个逆序对。
第五次操作:经过 1 轮冒泡排序后排列变为 {2,1,3},1 个逆序对。
第六次操作:经过 2 轮冒泡排序后排列变为 {1,2,3},0 个逆序对。
【数据范围与提示】
对于测试点 1 ~ 2:n,m ≤ 100。
对于测试点 3 ~ 4:n,m ≤ 2000。
对于测试点 5 ~ 6:交换操作个数不超过 100。
对于所有测试点:2 ≤ n,m ≤ 2 × 105,ti ∈ {1,2},1 ≤ x < n,0 ≤ k < 231。
【时间限制】
1.0s
【空间限制】
256MB
【上传文件】
上传c, cpp或pas语言源程序,文件名应依次为bubble.c, bubble.cpp, bubble.pas。
【解析】
【代码】
最小环
【题目描述】
给定一个长度为 n 的正整数序列 ai,下标从 1 开始编号。我们将该序列视为一个首尾相邻的环,更具体地,对于下标为 i,j(i ≤ j) 的两个数 ai,aj,它们的距离为 min(j-i,i+n-j)。
现在再给定 m 个整数 k1,k2,…,km,对每个 ki(i=1,2,…,m),你需要将上面的序列 ai 重新排列,使得环上任意两个距离为 ki 的数字的乘积之和最大。
【输入格式】
从文件ring.in中读入数据。
第一行两个正整数 n,m,表示序列长度与询问数。
接下来一行 n 个正整数表示 ai。
接下来 m 行每行一个非负整数表示 ki。
【输出格式】
输出到文件ring.out中。
共 m 行,每行一个整数表示答案。
【样例1输入】
6 3
1 2 3 4 5 6
0
1
2
【样例1输出】
91
82
85
【样例1解释】
ki=0 时:答案为每个数平方的和。
ki=1 时:一种最优方案:{3,1,2,4,6,5}。
答案为 3 × 1 + 1 × 2 + 2 × 4 + 4 × 6 + 6 × 5 + 5 × 3 = 82。
ki=2 时:一种最优方案:{3,6,1,4,2,5}。
答案为 3 × 1 + 1 × 2 + 2 × 3 + 6 × 4 + 4 × 5 + 5 × 6 = 85。
【数据范围与提示】
对于所有测试数据:1 ≤ m ≤ n ≤ 2 × 105,0 ≤ k ≤ ⌊n/2⌋,1 ≤ ai ≤ 105。
每个测试点的具体限制见下表:
测试点编号 | n ≤ | 特殊性质 |
---|---|---|
1 | 10 | 无 |
2 | 18 | 无 |
3 | 36 | n 为偶数且 m=1,k=2 |
4,5 | 1000 | m ≤ 10,k=1 |
6 | 50 | m ≤ 10,k ≤ 2 |
7,8 | 3000 | 无 |
9,10 | 2 × 105 | 无 |
【时间限制】
2.0s
【空间限制】
256MB
【上传文件】
上传c, cpp或pas语言源程序,文件名应依次为ring.c, ring.cpp, ring.pas。