题目地址:http://acm.uestc.edu.cn/problem.php?pid=1615
题目分析:作者定义了一个序列Saya infinite series(简称Saries),我们用A(n)表示。A(n)由两个正整数C和d唯一确定。而定义方法则是一个递推关系,根据n mod 4的余数决定A(k)和A(k-1)的关系:
n mod 4 == 1:A(k-1) + d --> A(k)
n mod 4 == 2:A(k-1) * d --> A(k)
n mod 4 == 3:A(k-1) - d --> A(k)
n mod 4 == 0:A(k-1) / d --> A(k)
我们现在分析下这个序列。假定我们选定了C和d,那么可以写出这个序列如下:
C、 C+d、 (C+d)*d、 (C+d-1)*d、
C+d-1、 C+2d-1、 (C+2d-1)*d、 (C+2d-2)*d、
C+2d-2、C+3d-2、 (C+3d-2)*d、 (C+3d-3)*d、
C+3d-3、 ... ...
分析一下就会发现:
1. A( 4*k+4 )总比A( 4*k )大d-1!(d是>=1的,我们发现子序列A(0)、A(4)、A(8)、A(12) ... ...是单调不降的,且都是正整数)
2. A(4*k+1)、A(4*k+2)、A(4*k+3) 和A(4*k)之间的关系是不变的,for all k,(就是说如果我们从A(4*k-1)将序列截断,从A(4*k)开始的子序列也是符合定义的Saries,此时新序列的C'==C+k*d-k);
3. 因为d>=1,所以A(4*k+1)、A(4*k+2)、A(4*k+3) 不会比A(4*k)小!(给定这样一个序列,可以知道A(0)==C等于序列的最小值,所以我们能很快得到C值,至于d的值,见下面分析)
作者又定义了一个序列Saya Sequence(简称Saquence),我们简称为S(n)。S(n)是A(n)中从能被4整除的n处截断的有限长序列(当然后面也要截断,不然就是无限长了)。经过上面分析2,我们不难分析出S(n)可以看做一个只在后面截断的A(n),S(0)==A(0)。
作者又定义一个S(n)的排列为Saya Permutation(简称为Sarmutation),我们叫做P(n)吧。题目让我们判断一个序列是否是一个P(n)。
解题思路:P(n)看做一个被从n之后截断的A(n)的重排列。从P(n)中找出C和d,然后重构出A(0)~A(n),判断P(0)~P(n)是否是A(0)~A(n)的重排列(这个建议大家把P(n)和A(n)排序后匹配)。
假定P(n)已按从小到大排好序。
寻找C:见上面的分析3;
寻找d:
1. d==1,此时原来的A(n)不就成了:C、C+1、C+1、C、C、C+1、C+1、C、C、C+1、C+1、C ... ...了吗?P(n)必然如下:C、C、C、C ... ... C+1、C+1、C+1 ...... 具体判断方法见下面checkDEqualTo1()函数;
2. d>1,此时很完美了!此时排序后的P(n)序列的第二小的元素将是C+d-1!而且C+d-1大于C(从上面我们列出的A(n)序列可以分析出来);具体判断方法见下面代码中checkDGreaterThan1()函数。
Ps:若是序列元素个数小于5,最好特判。
源代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int p[1005],a[1005];
bool cmp(int x,int y)
{
if(x<y)
return true;
return false;
}
bool checkDEqualTo1(int C,int d,int n)
{
int i,x,y;
x=y=0;
for(i=0; i<n; i++)
{
if(p[i]==C)
x++;
else if(p[i]==C+1)
y++;
else
return false;
}
if(x==y || ((x==y+1 || x==y-1) && x%2==1))
return true;
return false;
}
bool checkDGreaterThan1(int C,int d,int n)
{
int i;
a[0]=C;
a[1]=C+d;
for(i=2; i<n; i++)
{
if(i%4==1)
a[i]=a[i-1]+d;
else if(i%4==2)
a[i]=a[i-1]*d;
else if(i%4==3)
a[i]=a[i-1]-d;
else
a[i]=a[i-1]/d;
}
sort(a,a+n,cmp);
for(i=0; i<n; i++)
{
if(a[i]!=p[i])
return false;
}
return true;
}
int main()
{
int T,n,i,C,d,sign;
cin>>T;
while(T--)
{
cin>>n;
for(i=0; i<n; i++)
scanf("%d",&p[i]);
sort(p,p+n,cmp);
if(n==2)//特判1:只有两个数C,C+d...
{
if(p[0]>0 && p[1]>p[0])
sign=1;
else
sign=0;
}
else if(n==3)//特判2:三个数C,C+d,(C+d)*d
{
if(p[0]>0 && p[1]>p[0] && p[2]%p[1]==0 && p[2]/p[1]==p[1]-p[0])
sign=1;
else
sign=0;
}
else if(n==4)//特判3:四个数C,C+d,(C+d)*d,(C+d-1)*d
{
if(p[0]>0 && ((p[0]==p[1] && p[1]==p[2]-1 && p[2]==p[3])/*d==1*/
|| (p[1]>p[0] && (d=p[1]-p[0]) && p[2]==(p[0]+d-1)*d && p[3]==(p[0]+d)*d)/*d>1*/))
sign=1;
else
sign=0;
}
else //n>=5
{
if(p[0]>0 && p[1]==p[0] && (C=p[0],d=1) && checkDEqualTo1(C,d,n)==true)
sign=1;
else if(p[0]>0 && p[1]>p[0] && (C=p[0],d=p[1]-p[0]+1) && checkDGreaterThan1(C,d,n)==true)
sign=1;
else
sign=0;
}
if(sign==1)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}