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 <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>
#include <map>
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<m;i++)
printf("%lld\n",ans[i]);
}
(感觉出题者好像伊比喜,害怕