• ARC122C Calculator 题解


    一、题目:


    二、思路:

    这道题又是个妙题。

    先看一个定理:齐肯多夫定理

    任何正整数都可以表示成若干个不连续的斐波那契数(不包括第一个斐波那契数)之和。这种和式被称为齐肯多夫表述法

    那么怎样找出齐肯多夫表述法呢?

    对于任何正整数,其齐肯多夫表述法都可以由贪心算法(即每次选出最大可能的斐波那契数)得到。


    那么齐肯多夫定理和这道题有什么关系吗?

    首先,如果不用操作1和操作2,交替使用操作3和操作4,得到的序列一定是斐波那契数列。我们考虑在这个操作序列中插入一些操作1和操作2,使得最终凑出正整数 (n) 来。

    具体来说,我们首先求出 (n) 的齐肯多夫表述法,并将选中的斐波那契数打上标记。设最大的选中的斐波那契数是第 (sz) 个。

    1. 依次从大到小扫描每个斐波那契数,即扫描 (fib(sz)sim fib(2))

    2. 设当前扫描到了 (fib(i))

      1. (fib(i)) 被打过标记,则根据 (i) 的奇偶性,输出操作1或者输出操作2.
      2. 否则,什么都不做。

      根据 (i) 的奇偶性输出操作3或者输出操作4.

    考虑这样为什么是正确的。假设我们当前在某个位置加了1,那么这个1到最后就会演变成一个斐波那契数。而这些1的演变过程是互不干扰的。

    三、代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
     
    using namespace std;
    #define FILEIN(s) freopen(s".in", "r", stdin);
    #define FILEOUT(s) freopen(s".out", "w", stdout)
    #define mem(s, v) memset(s, v, sizeof s)
     
    inline long long read(void) {
        long long x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
        while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return f * x;
    }
     
    const int maxn = 100;
     
    int sz;
    long long f[maxn], n;
     
    int opt[maxn], tot;
    bool tag[maxn];
     
    int main() {
        n = read();
        if (n == 1) {
            printf("1
    1
    ");
            return 0;
        }
        f[1] = 1; f[2] = 1;
        for (int i = 3; ; ++ i) {
            f[i] = f[i - 1] + f[i - 2];
            if (f[i] > n) { 
                sz = i - 1; break;
            }
        }
        {
            int i = sz;
            while (n) {
                if (n >= f[i]) { n -= f[i]; tag[i] = true; }
                -- i; 
            }
        }
        for (int i = sz; i >= 2; -- i) {
            if (tag[i]) {
                if (i % 2 == 0) opt[++ tot] = 2;
                else opt[++ tot] = 1;
            }
            if (i % 2 == 0) opt[++ tot] = 3;
            else opt[++ tot] = 4; 
        }
        printf("%d
    ", tot);
        for (int i = 1; i <= tot; ++ i) 
            printf("%d
    ", opt[i]);
        return 0;
    }
    
  • 相关阅读:
    NIFI简介
    STM32L4R9xxxx图形加速器DMA2D实例使用——32位带alpha透明通道的位图ARGB8888显示时地址对齐问题
    25、如何计算车辆的出车次数?
    26、计算每年每月每天的数据
    11、【打印】打印发票—如何在页面合适地打印发票?
    12、如何将pdf改成word文档呢?
    2、如何设置签名?
    1、outlook邮箱如何撤回邮件?
    【其他】在洛谷上的最优解记录
    【笔记】积性函数、莫比乌斯反演
  • 原文地址:https://www.cnblogs.com/little-aztl/p/14880260.html
Copyright © 2020-2023  润新知