Split the Number - 第四届全国中医药院校大学生程序设计竞赛

问题描述

There is an infinite integer sequence f_1,f_2,f_3,..., where f_1=1,f_2=2,f_i=f_{i-1}+f_{i-2}(i >= 3).

You are given two positive integers n and k, your task is to check whether n can be split into k integers a_1,a_2,...,a_k, where a_1,a_2,...,a_k∈f and a_1+a_2+...+a_k=n. Note that you can split n into same integers, for example, 10=5+5=f_4+f_4.

输入

The first line of the input contains an integer T(1 <= T <= 100000), denoting the number of test cases.

In each test case, there is one integer n(1 <= n,k <= 10^{18}) in the first line.

输出

For each test case, print a single line. If it is possible to split n into k integers, print Yes, otherwise print No.

样例输入

4
10 1
10 2
5 1
12 2

样例输出

No
Yes
Yes
No

解题思路

在做这道题之前,首先得了解一个东西。

任何一个正整数一定能分解成若干个不重复且不相邻的斐波那契数之和

这个就是Zeckendorf理论,详见《任何一个自然数能被不相同的斐波那契数之和表示 - 知乎》。

有了这个理论基础,那么这个问题用贪心算法就会变得特别容易。

思路就是:每次找离数字n最近的斐波那契数,然后n -= 这个斐波那契数。

由于斐波那契数列增长得特别快,所以,我们可以直接打表。

long long a[] = {1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,
196418,317811,514229,832040,1346269,2178309,3524578,5702887,
9227465,14930352,24157817,39088169,63245986,102334155,
165580141,267914296,433494437,701408733,1134903170,1836311903,
2971215073,4807526976,7778742049,12586269025,20365011074,
32951280099,53316291173,86267571272,139583862445,225851433717,
365435296162,591286729879,956722026041,1548008755920,
2504730781961,4052739537881,6557470319842,10610209857723,
17167680177565,27777890035288,44945570212853,72723460248141,
117669030460994,190392490709135,308061521170129,498454011879264,
806515533049393,1304969544928657,2111485077978050,3416454622906707,
5527939700884757,8944394323791464,14472334024676221,
23416728348467685,37889062373143906,61305790721611591,
99194853094755497,160500643816367088,259695496911122585,
420196140727489673,679891637638612258,1100087778366101931,
1779979416004714189,2880067194370816120,4660046610375530309,
7540113804746346429};

打表挺容易的,本文不叙述。

那么我们的任务便是在这个数组中寻找离n最近的一个数字。

寻找的过程,我们可以用c++stl的函数upper_bound,从而来找一个比n大的数字,然后- 1来获得一个<= n的数字。

while (k --)
{
    v = *(upper_bound(a, a + 91, n) - 1);
    n -= v;
    if (n == 0) break;
}

上述代码就是在数组里寻找,找到一个<=n的数字v之后,n减去他,之后继续找一直到n = 0为止。

那么这个时候如果k还没用完呢?题目要求是分解成k个数字。

没关系,因为每个在斐波那契数列中的数字都能分解成另外2个数字,而且题目说还可以重复,那不就更容易了吗。

但是呢,得注意一把,如果k太大,都比n都要大了,那肯定不行啊,最小的斐波那契数也就只有1,所以说,判断一下即可。

if (k > n) {
    printf("No\n");
    continue;
}

好了,唯一要注意的就是得开long long

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <vector>
#include <list>
#include <set>
#include <utility> // pair
#include <map>
#include <iostream>
#include <sstream>
#include <algorithm> // sort
#include <string>
#include <stack>
#include <queue>
#include <fstream>

using namespace std;

#define ll long long
#define uchar unsigned char
#define ushort unsigned short
#define uint unsigned int
#define ulong unsigned long
#define ull unsigned long long

#define pi acos(-1)

#define mx(a,b) (a) > (b) ? (a) : (b)
#define mn(a,b) (a) < (b) ? (a) : (b)
#define mem(a,b) memset(a,b,sizeof(a))
#define fre(a) freopen(a,"r",stdin)

#define itn int
#define nit int
#define inr int
#define mian main
#define ednl endl
#define fro for
#define fir for
#define reutrn return
#define retunr return

int main()
{
    ll a[] = {1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903,2971215073,4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,86267571272,139583862445,225851433717,365435296162,591286729879,956722026041,1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,17167680177565,27777890035288,44945570212853,72723460248141,117669030460994,190392490709135,308061521170129,498454011879264,806515533049393,1304969544928657,2111485077978050,3416454622906707,5527939700884757,8944394323791464,14472334024676221,23416728348467685,37889062373143906,61305790721611591,99194853094755497,160500643816367088,259695496911122585,420196140727489673,679891637638612258,1100087778366101931,1779979416004714189,2880067194370816120,4660046610375530309,7540113804746346429};
    int T;
    scanf("%d",&T);
    ll n,k;
    ll v;
    while (T --)
    {
        scanf("%lld %lld",&n,&k);
        if (k > n) {
            printf("No\n");
            continue;
        }
        while (k --)
        {
            v = *(upper_bound(a, a + 91, n) - 1);
            n -= v;
            if (n == 0) break;
        }
        if (n == 0) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341