Problem 1080 奇怪的数列
Accept: 199 Submit: 343 Time Limit: 1000 mSec Memory Limit : 32768 KB
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
Source
FJNU Preliminary 2005
解决方案
本题主要是找规律来逆推多次,直到求出“根状态”,以题目描述中所给的例子来讲
0 6 0 8 0
6 0 14 0 8
6 20 0 22 0
-
假设我们只知道[3](第三排的元素),那么我们就应该先找出从[3]逆推出[2]的方法
-
先从[3][5](第三排第五个元素)来看(为什么呢,因为[3][5]仅仅只有可能来自[2][4]的二分),所以[2][4]就等于[3][5]
-
得到[2][4]之后,再根据[3][3]=[2][4]+[2][2]来求出[2][2]
-
这也就是说我们已知[3](第三排)要求[2],现在已经能求出[2][n-1](第二排倒数第二个元素)、[2][n-3]……以此类推
-
接下来考虑,当n为偶数或奇数各会发生什么,如本例n=5,是奇数,按照3.求到[2][2]为0后,根据[3][1]=[2][1]+[2][2],即可求出[2][1]。那么如果n是偶数,按照3.我们最后会直接求得[2][1],然后可以求出[2][2]。
-
进行到这里,n为奇数时,我们已经求出了[2][偶数](第二排的偶数项元素)和[2][1];n为偶数时,我们已经求出了[2][奇数]和[2][2]。
-
接下来以n为奇数为例继续,根据[3][2]=[2][1]+[2][3]求出[2][3]=20-6=14。以此类推可以把[2]都求出来。
-
根据1-6的规律方法就完成了一次逆推。那么如何判断逆推到什么情况不可再逆推了呢?也就是如何判断“根状态”呢?其实只要“根状态”再逆推一次,就会出现负数,只要逆推完发现负数,就可以知道逆推前的就是“根状态”了。
接下来是代码
//转载自:https://blog.youkuaiyun.com/zhuxingfu0625/article/details/7479806
#include<iostream>
using namespace std;
int main()
{
int t[2][100], i, k, n, Case;
bool flag;
cin >> Case;
while (Case--)
{
cin >> n;
for (i = 0; i < n; ++i)
cin >> t[0][i];
k = 0;
flag = true;
while (flag)
{
t[(k + 1) % 2][n - 2] = t[k][n - 1];
for (i = n - 4; i >= 0; i -= 2)
t[(k + 1) % 2][i] = t[k][i + 1] - t[(k + 1) % 2][i + 2];
if (i == -2)
{
i = 1;
t[(k + 1) % 2][1] = t[k][0] - t[(k + 1) % 2][0];
}
else if (i == -1)
{
i = 0;
t[(k + 1) % 2][0] = t[k][0] - t[(k + 1) % 2][1];
}
for (i += 2; i <= n - 1; i += 2)
t[(k + 1) % 2][i] = t[k][i - 1] - t[(k + 1) % 2][i - 2];
for (i = 0; i <= n - 1; ++i)
{
if (t[(k + 1) % 2][i] < 0)
flag = false;
else
k = (k + 1) % 2;
}
}
for (i = 0; i <= n - 2; ++i)
cout << t[k][i] << " ";
cout << t[k][n - 1] << endl;
}
return 0;
}