题目描述:对于一个n元组(a1,a2,......an),可以对于每个数求出它和下一个数的差的绝对值,得到一个新的n元组(|a1-a2|,|a2-a3|,......|an-a1|)。重复这个过程,得到的序列称为Ducci序列,例如:(8,11,2,7)->(3,9,5,1)->(6,4,4,2)->(2,0,2,4)->(2,2,2,2)->(0,0,0,0)。也有的序列最终会循环。输入n元组(3<=n<=15),你的任务是判断它最终变成0还是循环。输入保证最多1000步就会变成0或者循环。
这一题比较搞笑,我最开始想复杂了,首先我把一个n元组转换成唯一的一个string,比如(8,11,2,7)转换成"8+11+2+7",然后对于每次转换的n元组用set存储起来,然后判断每一次计算产生的新的n元组产生的字符串是否已经产生过,若产生过则为“LOOP”。很遗憾的是,这种做法超时了。
然后我就一直思考怎么能够最快的,判断计算产生的新的n元组以前是否产生过,可惜的是多次尝试都是超时。后来重新审题发现一个关键,就是Ducci序列最终一定会是循环,或者是“0”序列。并且测试用例都是在1000次中就可以得到结果,所以可以采取最直接的方法,在1000次的循环中,判断新的n元组是否为“0”n元组,否则就是循环。实际在本题中,循环200次就足够了。。。我这里用了vector,我想直接用数组应该会更快一点。
代码如下(vs2012运行通过):
// 1594.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
using namespace std;
vector<int> trans(vector<int> a)
{
vector<int> b;
for(int i=0;i<a.size();i++)
{
b.push_back(abs(a[i]-a[(i+1)%a.size()]));
}
return b;
}
bool isZero(vector<int> a)
{
for(int i=0;i<a.size();i++)
{
if(a[i]!=0)
return false;
}
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
int T;
cin>>T;
for(int i=0;i<T;i++)
{
vector<int> data;
int n;
cin>>n;
for(int j=0;j<n;j++)
{
int num;
cin>>num;
data.push_back(num);
}
bool flag = false;
for(int m=0;m<1000;m++)
{
if(isZero(data))
{
flag = true;
cout<<"ZERO"<<endl;
break;
}
data = trans(data);
}
if(flag==false)
{
cout<<"LOOP"<<endl;
}
}
return 0;
}