CSU暑期集训day04_递推_动态规划

题目:

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.

Sample Input

3    1

Sample Output

000

题目大意:

    给出01字符串的长度,字符串要满足不能有相邻两个1,给出序号k,求出按字典序排列的第k个满足要求的字符串。

解题思路:

    先求出每个长度下满足条件的字符串的个数,用动态规划,设f[i][1]和f[i][0]是长度为i且以1和0开头的满足条件的字符串的数量,如果第一位是1,则第二位一定是0,如果第一位是0,则第二位可以是0和1,所以有转换方程:f[i][1]=f[i-1][0],f[i][0]=f[i-1][1]+f[i-1][0]。初始状态f[1][1]=1,f[1][0]=0。

    知道了各种长度字符串的数量如何求出第k个字符串呢?我们需要求的长度为n的字符串按字典序排列的话一定是首位为“0”的排在前面,后面是首位为“1“的字串,所以如果k小于等于首位为“0”的字符串的数量(f[n][0]),则可以知道目标字符串的首位一定是“0”,在这种情况下,我们知道当首位都是相同的“0”时,剩下的n-1位字符串按字典序仍然是首位(即长度为n的字符串的第二位)为“0”的排在前面,所以继续用这种方式判断首位是否是“0”;那如果判断的结果是k大于首位为“0”的字符串的数量怎么办呢?这时候该位的字符串是“1”,与上面的情况不同的时,这时候要将k的值减去f[n][0],这是因为进行n-1长度的字符串比较时,在首位都为“1”的情况下,这些字符串在整体所有字符串的位置已经位于所有首位为“1”的字符串后面。

代码:

#include <iostream>

using namespace std;

int main(){
    int n;
    long long int k;
    int f[46][2];
    f[1][0]=1;
    f[1][1]=1;
    for(int i=2;i<44;i++){
        f[i][1]=f[i-1][0];
        f[i][0]=f[i-1][1]+f[i-1][0];
    }
    while(cin>>n>>k){
        if(k>f[n][1]+f[n][0]){
            cout<<-1<<endl;
            continue;
        }
        while(n){
            if(f[n][0]>=k)cout<<'0';
            else{
                k=k-f[n][0];
                cout<<'1';
            }
            n--;
        }
        cout<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42774699/article/details/81226165
今日推荐