一道防AK的好题【数列】

Time Limit 2000 ms Memory Limit 131072 KBytes Judge Standard Judge


Description

Czy手上有一个长度为n的数列,第i个数为xi。

他现在想知道,对于给定的a,b,c,他要找到一个i,使得a * (i+1) * xi^2+(b+1) * i * xi+(c+i)=0成立。(“ * ”号为乘号)

如果有多个i满足,Czy想要最小的那个i。

Czy有很多很多组询问需要你回答,多到他自己也不确定有多少组。所以在输入数据中a=b=c=0标志着Czy的提问的结束。

更加糟糕的是,Czy为了加大难度,决定对数据进行加密以防止离线算法的出现。

假设你在输入文件中读到的三个数为a0,b0,c0,那么Czy真正要询问的a=a0+LastAns,b=b0+LastAns,c=c0+LastAns.

LastAns的值是你对Czy的前一个询问的回答。如果这是第一个询问,那么LastAns=0。 所有的询问都将会按上述方式进行加密,包括标志着询问的结束的那个询问也是这样。

Input Format

输入文件为 seq.in

输入文件第一行包含一个整数n,表示数列的长度。

输入文件第二行包含n个整数,第i个数表示xi的值。

接下来若干行,每行三个数,表示加密后的a,b,c值(也就是上文所述的a0,b0,c0)

Output Format

输出文件为 seq.out

包含若干行,第i行的值是输入文件中第i个询问的答案。注意,你不需要对标志着询问结束的那个询问作答。

同时,标志着询问结束的询问一定是输入文件的最后一行。也就是,输入文件不会有多余的内容。

Sample Input

5
-2 3 1 -5 2
-5 -4 145
-1 -6 -509
-9 -14 40
-3 -13 21
-3 -3 -3

Sample Output

5
4
3
3

Hint

对于40%的数据,满足N<=1000,需要作出回答的询问个数不超过1000.

对于100%的数据,满足N<=50000,需要作出回答的询问个数不超过500000,xi的绝对值不超过30000,解密后的a的绝对值不超过50000,解密后的b的绝对值不超过10^8,解密后的c的绝对值不超过10^18.


【题解】

 为何说这是一道防ak的好题呢,我觉得这题主要玩的是心理吧,首先用一个强制在线骗过了许多人,(刚看到强制在线以及那个巨大的数据范围的我完全是一脸懵逼),据说当时出题者还是把这题放在最后一题233,那么许多人肯定就惯性思维的觉得这肯定不是很简单的题目,再看数据范围正好很适合nlogn的算法,一堆和我一样懵逼的小朋友可能就开始想数据结构或者二分答案,后来实在是想不出来,就很有可能尝试用数学方法做这题(因为我就是这样,然而我根本想不到233)。

现在来讲讲正解,题目的玄机之处就是最后一次询问的a,b,c一定是0,且题目的强制在线规则是a=a0+LastAns,b=b0+LastAns,c=c0+LastAns.

然后就惊奇的发现,通过最后一次询问(好吧也不算询问,就是000),可以得到倒二次的答案,然后把倒二次的答案与倒二次的a0,b0,c0带入式子就可以算出倒三次的答案,代码也特别好打。

详见代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
long long i,j,k,l,m,n;
long long x[55000],a[550000],b[550000],c[550000],p[55000],q[55000],ans[550000];

int main()
  {
  //	freopen("1731.in","r",stdin);
  	scanf("%lld",&n);
  	for (i=1;i<=n;i++) scanf("%lld",&x[i]),p[i]=x[i]*x[i]*(i+1),q[i]=i*x[i];
  	for (m=1;~scanf("%lld%lld%lld",&a[m],&b[m],&c[m]);m++);m--;ans[m-1]=0-a[m];
    for (i=m-1;i>1;i--)
      {
      	ans[i-1]=(0-(p[ans[i]]*a[i]+(b[i]+1)*q[ans[i]]+c[i]+ans[i]))/(p[ans[i]]+q[ans[i]]+1);
	  }
	for (i=1;i

(感觉出题者好像伊比喜,害怕


你可能感兴趣的:(noip模拟)