FZU1080 奇怪的数列

Posted dlvguo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FZU1080 奇怪的数列相关的知识,希望对你有一定的参考价值。

技术图片 Problem Description  题目链接

有一个长度为n (1<n<=100) 的数列,其中一些元素是正整数,其余元素是0。这些正整数会同时加倍,并将加倍后的数二等分后向左右两侧的元素转移,从而从一个状态转入其后继状态,如下图的一个状态:

0 6 0 8 0
经一次加倍转移后,其后继状态为:
6 0 14 0 8
特别要注意的是:第一个元素的数加倍后,向左边移动的数又回到原处。最后一个元素的数加倍后,向右边移动的数消失。如上述状态再经一次加倍转移后的后继状态是:
6 20 0 22 0
有些状态不可能是另一些状态的后继状态,我们称这样状态为“根状态”。给出一个状态,求它的根状态。

技术图片 Input

第一行仅包含一个表示测试例个数的正整数n。以下 2n 行为测试例的输入数据。
每个测试例输入两行,第一行是一个正整数,为数列的长度。第二行为给定的一个数列,两数之间用一个空格隔开。

技术图片 Output

每个测试例输出一行,包含数列的根状态下的各个元素,两数之间用一个空格隔开。

技术图片 Sample Input

2
5
5 10 1 9 0
8
1 0 1 1 0 3 9 1

技术图片 Sample Output

0 0 1 0 0
1 0 1 1 0 3 9 1
#include <iostream>
#include <stdio.h>
using namespace std;

/*  思路:找规律将矩阵回退,当下一个矩阵中含有负数的时候,说明当前矩阵为根矩阵:如n为奇数的时候
      1层:  0  6  0  8  0
      2层:  6  0  14 0  8 
      3层:  6  20 0  22 0
      因为最右边向右移会消除于是有:[2][4]=[3][5]  
      之后从右向左递推 [2][2]=[3][5]-[2][4]...
      之后从左向右递推 [2][3]=[3][2]-[3][1]...  
*/

int main()
{
    int num[2][105] = {0};
    int n, t;
    scanf("%d", &n);
    while (n--)
    {
        int now = 0, pre = 1;
        bool tag = false;
        scanf("%d", &t);
        for (int i = 1; i <= t; i++)
        {
            scanf("%d", &num[now][i]);
        }
        //计算上一个数组含有负数的时候 说明当前数组为根
        while (!tag)
        {
            num[pre][t - 1] = num[now][t];
            for (int i = t - 3; i >= 1; i -= 2)
            {
                num[pre][i] = num[now][i + 1] - num[pre][i + 2];
                if (num[pre][i] < 0)
                {
                    tag = true;
                    break;
                }
            }
            if (tag)
                break;
            // 注意n为奇的时候 [x][1]要另外算 循环上述循环不会遍历到
            if (t % 2)
            {
                num[pre][1] = num[now][1] - num[pre][2];
                if (num[pre][1] < 0)
                {
                    break;
                }
            }
            for (int i = 3; i <= t; i += 2)
            {
                num[pre][i] = num[now][i - 1] - num[pre][i - 2];
                if (num[pre][i] < 0)
                {
                    tag = true;
                    break;
                }
            }
            if (tag)
                break;
            now = pre;
            pre = (pre + 1) % 2;
        }
        printf("%d", num[now][1]);
        for (int i = 2; i <= t; i++)
        {
            printf(" %d", num[now][i]);
        }
        cout << endl;
    }
}

 

以上是关于FZU1080 奇怪的数列的主要内容,如果未能解决你的问题,请参考以下文章

fzu 2184 逆序数还原

FZU 2020 组合 (Lucas定理)

FZU 2113 BCD Code 数位dp

PTA乙级 (1049 数列的片段和 (20分))

1049. 数列的片段和(20)

1049 数列的片段和 (20 分)