没错,这篇文章不是在我学OI时写的,而是在实实在在的2020年写的。这似乎预示着我将不得不重回竞赛的怀抱了,祝我好运吧。
题目大意: 对一个长为 n n n的数列 { a n } \{a_n\} {an},有以下两个操作: 1. 1. 1.求和操作:数列 { a 1 , a 2 , . . . , a n } \{a_1,a_2,...,a_n\} {a1,a2,...,an}变为 { a 1 , a 1 + a 2 , . . . , a 1 + a 2 + . . . + a n } \{a_1,a_1+a_2,...,a_1+a_2+...+a_n\} {a1,a1+a2,...,a1+a2+...+an}; 2. 2. 2.翻转操作:数列 { a 1 , a 2 , . . . , a n } \{a_1,a_2,...,a_n\} {a1,a2,...,an}变为 { a n , a n − 1 , . . . , a 1 } \{a_n,a_{n-1},...,a_1\} {an,an−1,...,a1}。 给定两个长为 n n n的数列 { a n } \{a_n\} {an}和 { b n } \{b_n\} {bn},问能不能对 { a n } \{a_n\} {an}进行有限次数的上述操作,使得整个数列各项和 { b n } \{b_n\} {bn}中的各项对应相等。如果能,输出最小操作次数,否则,输出 − 1 -1 −1。 你需要在 1 s 1s 1s内解决 T T T组数据。 数据范围: T ≤ 20 , n ≤ 1 0 5 , 1 ≤ a 1 , . . . , a n , b 1 , . . . , b n ≤ 1 0 12 T\le 20,n\le 10^5, 1\le a_1,...,a_n,b_1,...,b_n \le 10^{12} T≤20,n≤105,1≤a1,...,an,b1,...,bn≤1012。
做法: 本题是一道思维题。 注意到一开始数列中的项都是正整数,因此在进行一次求和操作后,整个数列必定是单调递增的。算上翻转操作,我们可以断定,只要进行过一次求和操作,则整个数列要么单调递增,要么单调递减。而连续进行两次翻转操作就和没翻转一样,所以最优的操作方法一定是求若干次和,然后翻转一次,然后继续往下,这样。 我们发现两种操作都是可逆的,也就是说,如果我们知道一个数列 { a n } \{a_n\} {an}经过一次求和或翻转后,得到一个数列 { b n } \{b_n\} {bn},而 { b n } \{b_n\} {bn}已知,我们可以用 O ( n ) O(n) O(n)的时间求得 { a n } \{a_n\} {an},且很显然, { a n } \{a_n\} {an}是唯一的。那么与其正着算,还不如从目标序列 { b n } \{b_n\} {bn}一步步倒回去,看它会不会在某个时刻和 { a n } \{a_n\} {an}相等。 如果 { b n } \{b_n\} {bn}单调递减,则它的前一步一定不是求和(因为求和操作后得到的数列必然是单调递增的),所以前一步只能是翻转,于是将它翻转过来,操作次数 + 1 +1 +1; 如果 { b n } \{b_n\} {bn}单调递增,则它的前一步可以是求和,也可以是翻转,但如果前一步是翻转,那么再前一步一定也是翻转(因为翻转一次后数列单调递减),前面说过连续翻转两次没有意义,因此有意义的前一步必然是求和,这时就对数列求一个差分(求前缀和的逆操作),操作次数 + 1 +1 +1; 这样循环下去,中间一直判断得到的每一个数列是否与 { a n } \{a_n\} {an}相等,如果相等就立刻退出,输出操作次数即可。如果某个时刻 { b n } \{b_n\} {bn}不单调了,那它要么就和 { a n } \{a_n\} {an}相等,要么就翻转一次后,和 { a n } \{a_n\} {an}相等,否则,我们就能得出无解的结论,输出 − 1 -1 −1。 这是一个可行的算法,那么它的时间复杂度如何呢?注意到连续多次求前缀和,数列中最大项的大小是指数级增长的,而目标序列中最大项也不会超过 1 0 12 10^{12} 1012,所以如果有解,那么求和次数最差也就是 log 1 0 12 \log 10^{12} log1012。而连续两次翻转是没有意义的,因此翻转最多只能夹在两次求和之间,所以最差也是 log 1 0 12 \log 10^{12} log1012次。所以上述循环的深度最多达到 log 1 0 12 \log 10^{12} log1012这个等级,而里面的差分、翻转都是 O ( n ) O(n) O(n)的,因此整个算法的时间复杂度为 O ( n log 1 0 12 ) O(n\log 10^{12}) O(nlog1012)。事实上要比这个数小不少,因为 log \log log的底数一般比 2 2 2大很多。 这样我们就解决了这个问题。