Consider all the sequences with length (0 < N < 44), containing only the elements 0 and 1, and no two ones are adjacent (110 is not a valid sequence of length 3, 0101 is a valid sequence of length 4). Write a program which finds the sequence, which is on K-th place (0 < K < 10 9) in the lexicographically sorted in ascending order collection of the described sequences.
Input
The first line of input contains two positive integers N and K.
Output
Write the found sequence or −1 if the number K is larger then the number of valid sequences.
Example
input | output |
---|---|
3 1 |
000 |
思路:先判断输入的K是否合法(一开始用组合里的隔板法判断长度,后来发现是个斐波那契数列,)
- 隔板法,用0将1隔开,考虑0的数量和1的数量就可以得到该长度下01字符串的种数
- 字符串的长度满足斐波那契数列,f(i)=f(i-1)+f(i-2),只要在长为i-2和i-1的字符串前加1或者0
然后要构造字典序第K小的序列,我们要根据K和f(i)的关系判断这一位是0还是1
#include<cstdio>
#include<string.h>
using namespace std;
long long fac[15];
long long num[50];
//长为N的字符串的可能数构成斐波那契数列
void init()
{
num[0] = 0;
num[1] = 2; num[2] = 3;
for (int i = 3; i <= 44; i++)
num[i] = num[i - 1] + num[i - 2];
}
////寻找长为N的字符串有几种可能性
//bool check(int N, int K)
//{
// if (num[N] != -1)
// {
// if (num[N] > K)
// return true;
// else
// return false;
// }
//
// long long res = 0;
// for (int i = 1; i <= N; i++)
// {
// if (N - (i - 1) < i)
// break;
// res += fac[N - (i - 1)] / fac[i] / fac[N - (i - 1) - i];
// }
// res++;
// num[N] = res;
// if (res >= K)
// return true;
// else
// return false;
//}
void findk(int N, int K)
{
int res[50]; //结果
for (int i = 1; i <= N; i++)
res[i] = 0;
int tail[50]; //末尾的个数
for (int i = 0; i < 50; i++)
tail[i] = 0;
int p = 0; //可能要改变的末尾的p个数
for (int i = 1; i <= N; i++)
if (K <= num[i])
{
p = i;
break;
}
int pos = 0;
for (int i = p; i >= 1; i--)
{
if (K == 1) //最后一位为0
{
for (; pos < p; pos++)
tail[pos] = 0;
break;
}
//K=num[i],则找字典序最大的情况
if (K == num[i])
{
for (; pos < p; pos++)
{
if (pos == 0)
tail[pos] = 1;
else if (tail[pos - 1] == 0)
tail[pos] = 1;
else if (tail[pos - 1] == 1)
tail[pos] = 0;
}
break;
}
else if (K < num[i] && K > num[i - 1])
{
tail[pos++] = 1;
K = K - num[i - 1];
}
else if (K < num[i] && K <= num[i - 1])
tail[pos++] = 0;
for (int i = N - p + 1, j = 0; i <= N; i++)
res[i] = tail[j++];
for (int i = 1; i <= N; i++)
printf("%d", res[i]);
printf("\n");
}
int main()
{
memset(num, -1, sizeof(num));
fac[0] = 1;
for (int i = 1; i <= 15; i++)
fac[i] = i * fac[i - 1];
int N, K;
init();
while (scanf("%d %d", &N, &K) != EOF)
{
if (K == 1)
{
for (int i = 1; i <= N; i++)
printf("0");
printf("\n");
}
else if (num[N] >= K)
findk(N, K);
else
printf("-1\n");
}
return 0;
}