Uva 1350 - Pinary 解题报告(斐波那契+二分)

96 篇文章 0 订阅

``Pinary" number is a positive number using only two digits ``0" and ``1" with usual rule that it must not begin with a 0, and the additional rule that two successive digits must not be both ``1". This means that the factor ``11" is forbidden in the string. So the allowed Pinary writings are 1, 10, 100, 101, 1000, 1001,..., 100010101010100010001 . For example, ``100101000" is a Pinary number, but neither ``0010101" nor ``10110001" are Pinary numbers.

Each Pinary number represents a positive integer in the order they appear (using length order, lexicographic order), that is, 1 is mapped to 1, 10 is mapped to 2. And 100, 101 and 1000 are mapped to 3, 4 and 5, respectively. You are to write a program to generate Pinary number representations for integers given.

Input 

Your program is to read from standard input. The input consists of T test cases. The number of test cases T is given in the first line of the input. Each test case starts with a line containing a postive integer 2 < K < 90, 000, 000 .

Output 

Your program is to write to standard output. Print exactly one line for each test case. For each test case, print the Pinary number representation for input integer. The following shows sample input and output for three test cases.

Sample Input 

3 
7 
2000 
22

Sample Output 

1010 
1001000001001000 
1000001
    

    解题报告: 求第k个没有前导0和连续1的01串。

    首先可以递推一下。用dp[i][j]表示长度为i,第一个数为j的串的数量。那么,dp[i][0]=dp[i-1][0]+dp[i-1][1], dp[i][1]=dp[i-1][0]。

    可以知道dp[i][1]满足斐波那契数列。对dp[i][1]预处理求和,得到sum数组。sum[i]就表示i位的符合条件的二进制串的数量。

    对输入的n进行二分查找,则那一位必定是首位1,而且表示的数的sum[i-1]+1。减去该数,遍历一遍。发现能减去时则减去,并且打印1,否则打印0。

    代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int maxn = 90000000;
int num[10000];
int sum[10000];
int top;

void init()
{
    num[2]=num[1]=1;
    sum[1]=1;sum[2]=2;
    for(int i=3;sum[i-1]<=maxn;i++)
    {
        num[i]=num[i-1]+num[i-2];
        sum[i]=sum[i-1]+num[i];
        if(sum[i]>=maxn)
        {
            top=i+1;
            break;
        }
    }
}

void work()
{
    int n;
    scanf("%d",&n);

    int pos = lower_bound(sum+1,sum+top,n)-sum;

    for(int i=pos;i;i--)
    {
        if(n>sum[i-1])
            printf("1"),n-=sum[i-1]+1;
        else
            printf("0");
    }
    puts("");
}

int main()
{
    init();

    int T;
    scanf("%d",&T);
    while(T--)
        work();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值