【题目】
T1(L2837) 晚餐队列安排
【题面】
为了避免餐厅过分拥挤,FJ要求奶牛们分2批就餐。每天晚饭前,奶牛们都会在餐厅前排队入内,按FJ的设想,所有第2批就餐的奶牛排在队尾,队伍的前半部分则由设定为第1批就餐的奶牛占据。由于奶牛们不理解FJ的安排,晚饭前的排队成了一个大麻烦。 第i头奶牛有一张标明她用餐批次D_i(1 <= D_i <= 2)的卡片。虽然所有N头奶牛排成了很整齐的队伍,但谁都看得出来,卡片上的号码是完全杂乱无章的。 在若干次混乱的重新排队后,FJ找到了一种简单些的方法:奶牛们不动,他沿着队伍从头到尾走一遍,把那些他认为排错队的奶牛卡片上的编号改掉,最终得到一个他想要的每个组中的奶牛都站在一起的队列,例如112222或111122。有的时候,FJ会把整个队列弄得只有1组奶牛(比方说,1111或222)。 你也晓得,FJ是个很懒的人。他想知道,如果他想达到目的,那么他最少得改多少头奶牛卡片上的编号。所有奶牛在FJ改卡片编号的时候,都不会挪位置。
输入输出格式
输入格式:
第1行: 1个整数:N * 第2..N+1行: 第i+1行是1个整数,为第i头奶牛的用餐批次D_i
输出格式:
一行: 输出1个整数,为FJ最少要改几头奶牛卡片上的编号,才能让编号变成他设想中的样子。
输入输出样例
说明
1 <= N <= 30000
【题解】
这道题的意思是由1和2组成的序列,要使这个序列的前一部分为1,后一部分为2需要至少改动几个数字?
分析:这道题的O(N^2)的算法很容易想到,在此不提。
要清楚对于第1题我们想要AC,而不是部分分!
仔细想来O (n^2)的算法可以改为O(n)的算法,优化如下:
首先把12串换为01串(我比较喜欢01串)
设立: a0[i]表示i位之前(不包括i位)有几个0;
a1[i]表示i位之前(不包括i位)有几个1;
b0[i]表示i位之后(不包括i位)有几个1;
b1[i]表示i位之后(不包括i位)有几个1;
这算下来是O(n)
遍历i?1---n,令t1=a1[i]+b0[i];
然后每一次遍历求最小值ans,ans=min(ans,t1)
因为0号排在前,1号排在后,所以只要取a1[]b0[]的和即可
最后打出ans即可
【反思】
本题考查读题“队伍的前半部分则由设定为第1批就餐的奶牛占据”如前面一批可能是2号奶牛的话只能拿63分,还有就是dp思想的问题,这道题的解答就是利用dp中的无后效性,所以完全可以按dp做,但是,这种方法“找断点”是最容易想到,实现起来相对容易些,是好方法。在平时落实好方法,在竞赛当中才会好好的用起来!
T2 归并排序求逆序对
【题面】
在一个旧式的火车站旁边有一座桥,其桥面可以绕河中心的桥墩水平旋转。一个车站的职工发现桥的长度最多能容纳两节车厢,如果将桥旋转180度,则可以把相邻两节车厢的位置交换,用这种方法可以重新排列车厢的顺序。于是他就负责用这座桥将进站的车厢按车厢号从小到大重新排列。他退休之后,火车站决定将这一工作自动化,其中一项重要的工作是编一个程序,从输入文件读入列车初始的车厢顺序,计算最少用多少步就能将车厢排序,把最少的步数记录在输出文件中。
输入:输入文件的每行是一用空格符分隔、n个元素的正整数数列,该数列记录了一列车初始的车厢顺序,当输入行的第一个数为0,表示文件结束。
输出:输出文件与输入文件有同样的行数。每一行只有一个整数记录了对应输入文件该行列车车厢排序所需的最少步数。(n<=100,000)
输入样例:4 3 2 10
输出样例:6
【题解】裸的归并排序求逆序对!
【程序】程序就不用看了吧!
【反思】没什么好反思的!
T3(L2227)洗牌机
【题面】
剀剀和凡凡有N张牌(依次标号为1,2,……,N)和一台洗牌机。假设N是奇数。洗牌机的功能是进行如下的操作:对所有位置I(1≤I≤N),如果位置I上的牌是J,而且位置J上的牌是K,那么通过洗牌机后位置I上的牌将是K。
剀剀首先写下数值1,2,……,N的一个随机排列:a1, a2, ..., aN。然后他这样来排列牌的顺序:位置ai 放置牌ai+1, (对1≤i≤N-1),而aN 放置牌a1。这样排列后,牌的顺序就为x1, x2, ..., xN。然后,他把这种顺序排列的牌放入洗牌机洗牌S次,得到牌的顺序为p1, p2, ..., pN。现在,剀剀把牌的最后顺序和洗牌次数告诉凡凡,要凡凡猜出牌的最初顺序x1, x2, ..., xN。
输入输出格式
输入格式:
第一行为整数N和S。1≤N≤1000,1≤S≤1000。第二行为牌的最终顺序p1, p2, ..., pN。
输出格式:
为一行,即牌的最初顺序x1, x2, ..., xN。
输入输出样例
输入样例#1:
5 2
4 1 5 3 2
输出样例#1:
2 5 4 1 3
【题解】
对于本题,我们只有一种骗分的办法,我这里是没有十分的把握说一定能够骗到多少分的,只能说我会尽力骗分的!(目测10分)
当然,对于一个多数据的题目只打一个数据显然是骗不到分的!
我这里提供的一种方式是暴力枚举每一种可能,推s次,若找出序列就打出!
平均的时间复杂度是O(n!*s/4)对于n=1000,是不可能在1s之内给出解答的!
那么我们先写这个暴力程序,再看看有没有什么新方法!
需要注意的是,可能存在多组解?!
但是我认为洛谷的数据有问题!
如果正常的话是能拿20分
总比没分好!
【反思】
不知道怎么做,毫无办法的情况下怎么骗分?
T4 第K小邪恶数
【题面】
邪恶数的定义:在全体实数中,因子只是13和7的数。
如:7是最小的邪恶数:7=7^1 接下来的邪恶数是 13 49 91
需要注意的是,邪恶数是完全没有数值上的规律的!
例如 7 是邪恶数,3是邪恶数 49 是邪恶数,中间的间隔貌似是几何指数级的递增
现在,有一个艰巨的任务要交给你,求出第k小的邪恶数!
(k<=10,000)
输入输出格式
输入格式:
一个整数k
输出格式:
一个数,第k小的邪恶数
输入输出样例
输入样例#1:
2
输出样例#1:
13
输入样例#2:
4
输出样例#2:
91
说明
对于20%的数据k<=100
对于100%的数据k<=10,000
【题解】
对于本题,考高精度的计算!这也是NOIP必考的算法之一,我们先来复习一下高精度算法:
高精度的复习 (点击进入)
算法其实很容易想到,输入k后将邪恶数以字符串(二维数组)的形式存在数组num[i]中对该数组进行模仿数字的快排(qsort)求num[k]即可!
时间复杂度为O(k^2*16w*log2 16w)
利用递推可以求
13^0*7^0 13^0*7^1 13^0*7^2(注意特判3^0*7^0不为第一个邪恶数)
13^1*7^0 13^1*7*1 13^1*7^2
13^2*7^0 13^2*7*1 13^2*7^2
……(一直算)
到13^k*7^0为止
然后快排num数组即可!
代码可能比较复杂!
我们需要的代码块:
求13^n 7^n的递归算法pow 时间复杂度 O(log 13^n)
就是怎么多!
现在让我们一个一个来实现!
相信你已经认真思考过了!现在你可以点击上面的超链接看看我是怎么做的?
于是我们要做的就剩下组合了!
其实组合还是很快的!这个程序大概100行左右
告诉大家的是第20个邪恶数是199927第100个邪恶数已经是6755066100601
第200个邪恶数是:2995508600908518877(需要等一会)
【提升】
注意对于上述程序,只能拿到k<=50的分数,为什么?
冗余的太厉害,例如输入20,邪恶数是199927但是按照上述算法,需要计算到13^k为止!而13^20=1900496377488079943880更加1,冗杂了多少倍?
基于此,我们应该想出更优化的程序,俗称剪枝!
上面的程序没有用到递推,而是递归,下面我们换用递推来看看是否快一点!
(下面这段程序是到13^(k/2)*7^(k/2)为止)
快了大概50%
对于冗余的解决,其实还可以这样来看待,不用枚举7的几次方和13的几次方,我们观察到前15个邪恶数分别是:
1 |
2 |
3 |
4 |
5 |
7 |
13 |
49 |
91 |
169 |
7^1 |
13^1 |
7^2 |
7^1*13^1 |
13^2 |
6 |
7 |
8 |
9 |
10 |
343 |
637 |
1183 |
2197 |
2401 |
7^3 |
7^2*13 |
7*13^2 |
13^3 |
7^4 |
11 |
12 |
13 |
14 |
15 |
4459 |
8281 |
15379 |
16807 |
28561 |
7^3*13 |
7^2*13^2 |
7^1*13^3 |
7^5 |
13^4 |
供大家思考。
在程序里,我发现这样一个有趣的地方初始的tx(最大限度)的参数可以自行调节并且一般不会对结果产生影响。希望大家探究这个tx的值和k之间存在何等关系。
【反思】
我个人认为觉得这道题目放在这里已经意义不大了!而且作为思维量较大的最后一题的数据范围也够庞大的,n^2的 算法都不一定能够过还要高精度!意义确实不大,如果k<=500的话再NOIP的竞赛当中是可能出现的,可以这么说这里的k<=10,000在1s之间在现有的编程环境下完全达不到!
【总结】
这套卷子难度有些,但是找到算法一般都能求解,特别是第4题,思维量特别的大,还可能无法满分的风险!而且耗时也很长,所以,这张卷子在没有任何外力帮助下考300分还是非常困难的,但是冲一冲还是可以进的!
希望大家,在今后的学习OI中多花时间在钻研算法上,这样才能更近一步!
(完)