InputThe first line of input contains two positive integers
N and
K.
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·OutputWrite the found sequence or −1 if the number
K is larger then the number of valid sequences.
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·Sample
| input | output |
3 1s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
| 000s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
|
Problem Author: Emil Kelevedzhiev
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·Problem Source: Winter Mathematical Festival Varna '2001 Informatics Tournament 答案如下:
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·1 using System;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
2 using System.IO;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
3 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
4 namespace Skyiv.Ben.Timuss<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
5 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
6 //http://acm.timus.ru/problem.aspx?space=1&num=1081s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
7 class T1081s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
8 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
9 static void Main()s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
10 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
11 new T1081().Run(Console.In, Console.Out);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
12 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
13 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
14 void Run(TextReader reader, TextWriter writer)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
15 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
16 string[] ss = reader.ReadLine().Split();s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
17 short[] bs = GetBinarys(int.Parse(ss[0]), int.Parse(ss[1]));s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
18 if (bs == null) writer.Write(-1);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
19 else for (int i = bs.Length - 1; i >= 0; i--) writer.Write(bs);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
20 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
21 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
22 short[] GetBinarys(int n, int k)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
23 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
24 short[] bs = new short[n];s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
25 int[] fib = GetFibonacci(n);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
26 for (int i = n + 2; k > 1; k -= fib)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
27 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
28 i = Seek(fib, i - 2, k);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
29 if (i >= n) return null;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
30 bs = 1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
31 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
32 return bs;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
33 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
34 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
35 int[] GetFibonacci(int n)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
36 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
37 int[] fib = new int[n + 1];s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
38 fib[0] = 1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
39 fib[1] = 2;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
40 for (int i = 2; i <= n; i++) fib = fib[i - 1] + fib[i - 2];s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
41 return fib;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
42 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
43 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
44 int Seek(int[] fib, int m, int k)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
45 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
46 for (int i = m; i >= 0; i--) if (fib < k) return i;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
47 return -1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
48 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
49 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
50 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
这道题要求给出第 K (0 < K < 109) 个 N (0 < N < 44) 位二进制数,该二进制数不得有相邻的“1”。由于时间限制是 0.5 秒,肯定不能使用蛮力搜索从 1 列举到 K。
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·我们以 N = 5 来分析看看有没有什么规律。如左图所示,我们发现该二进制数最左边的“1”开始在第几个数之后出现是很规律的,如下所示(左图中红色粗框中的数):
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·1, 2, 3, 5, 8, 13, ...
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·也就是说,后项等于前二项之和。这不正是扔掉第一项后的斐波那契 ( Fibonacci ) 数列吗?
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·于是,程序在第 35 到 42 行的 GetFibonacci() 方法中计算出该数列。然后在第 22 到 33 的 GetBinarys() 方法中计算出第 K 个满足条件的二进制数。该方法在第 26 到 31 行的循环中从高位到低位设定“1”(如左图中红色细框所示)。
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·请注意,左图中两块阴影部分的内容是相同的,都代表了 N = 3 的情况。也就是说,N = 5 的最低三位是在重复 N = 3 的情况。并且由于该二进制数不得有相邻的“1”,所以在程序第 28 行使用 i - 2 而不是 i - 1 作为第 2 个参数调用 Seek() 方法,然后在第 30 行将该二进制数的第 i 位设为“1”。最后在第 26 行 k -= fib,以进入下一轮循环,直到 k 降低到 1 而结束循环。
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·本程序的算法应该是最优的,其时间复杂度为 O(N)。本程序的
运行时间是 0.078 秒,其 C++ 版本程序的运行时间是 0.001 秒。
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·我们知道,斐波那契 ( Fibonacci ) 数列定义如下:
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·F1 = 1, F2 = 1, Fn = Fn-1 + Fn-2 (n > 2)
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·她的前几项如下:
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·她的通项公式如下:
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·Fn = ( (1+ √5) / 2 )n / √5 - ( (1- √5) / 2 )n / √5 ≈ O(1.618n)
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·由于程序中的 fib 数组的下标是从 0 开始,且扔掉了斐波那契 ( Fibonacci ) 数列的第一项,所以 fib[n] = Fn+2。
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·从上图中可以看出,N 位没有相邻的“1”的二进制数共有 fib[N] 个,也就是 FN+2 ≈ O(1.618N+2) 个。
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·所以,如果使用蛮力搜索从 1 列举到 K,其时间复杂度约为 O(1.618N+2)。
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·在本题中,要求给出第 K (0 < K < 109) 个 N (0 < N < 44) 位没有相邻的“1”的二进制数。实际上 fib[43] = F45 = 1,134,903,170 ≈ 109。所以 K 和 N 的大小是匹配的。
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·我用 C++ 语言写了一个蛮力搜索从 1 列举到 K 的程序,如下:
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·1 // http://acm.timus.ru/problem.aspx?space=1&num=1081s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
2 #include <iostream>s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
3 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
4 const int N_MAX = 43;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
5 __int64 mask[N_MAX + 1];s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
6 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
7 void init(int n)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
8 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
9 mask[0] = 1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
10 for (int i = 1; i <= n; i++) mask = mask[i - 1] << 1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
11 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
12 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
13 int valid(__int64 bin, int n)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
14 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
15 while (n >= 0 && (bin & mask[n]) == 0) n--;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
16 while (n > 0)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
17 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
18 if (bin & mask[--n]) return 0;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
19 while (n >= 0 && (bin & mask[n]) == 0) n--;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
20 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
21 return 1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
22 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
23 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
24 __int64 getBinary(int n, int k)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
25 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
26 __int64 bin = 0;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
27 for ( ; k > 0; bin++)s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
28 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
29 if (bin >= mask[n]) return -1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
30 if (valid(bin, n - 1)) k--;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
31 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
32 return bin - 1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
33 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
34 s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
35 int main()s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
36 {s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
37 int n, k;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
38 std::cin >> n >> k;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
39 init(n);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
40 __int64 bin = getBinary(n, k);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
41 if (bin < 0) std::cout << -1;s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
42 else for (int i = n - 1; i >= 0; i--) std::cout << ((bin & mask) ? 1 : 0);s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
43 }s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·将该程序提交到
Timus Online Judge,果然
超时:
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·上图中,ID 为 2144627 的记录(运行到 0.515 秒后因为超时而被终止)就是蛮力搜索程序的运行结果,而 ID 为 2141944 的记录(运行时间为 0.001 秒)就是将前面 C# 程序翻译为 C++ 程序的运行结果。
s<¦Þã}æwww.netcsharp.cnmåÑþ{G ·