数列(倒推)

CYX 手上有一个长度为n 的数列,第i 个数为xi。
她现在想知道,对于给定的a,b,c,她要找到一个i,使得a*(i + 1) * xi2 + (b + 1) * i * xi + (c + i) = 0成立。

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

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

更加糟糕的是,CYX 为了加大难度,决定对数据进行加密以防止离线算法的出现。
假设你在输入文件中读到的三个数为a0,b0,c0,那么CYX 真正要询问的a = a0 + LastAns,b = b0 + LastAns,c = c0 + LastAns。

LastAns的值是你对CYX 的前一个询问的回答。如果这是第一个询问,那么LastAns=0。

所有的询问都将会按上述方式进行加密,包括标志着询问的结束的那个询问也是这样。

【输入】
输入文件为 seq.in
输入文件第一行包含一个整数n,表示数列的长度。
输入文件第二行包含n 个整数,第i 个数表示xi 的值。
接下来若干行,每行三个数,表示加密后的a,b,c 值(也就是上文所述的a0,b0,c0)
【输出】
输出文件为 seq.out
包含若干行,第i 行的值是输入文件中第i 个询问的答案。注意,你不需要对标志着询问结束的那个询问作答。
同时,标志着询问结束的询问一定是输入文件的最后一行。也就是,输入文件不会有多余的内容。

【输入输出样例】
seq.in 

5 -2 3 1 -5 2
-5 -4 145

-1 -6 -509

-9 -14 40

-3 -13 21

-3 -3 -3

seq.out

5

4

3

3

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

N <= 50000,询问个数m不超过500000,所以O(nm)过不了,但是我们观察到最后的a,b,c解密后为0,那么我们可以以此倒推出前一个的答案,以此类推,时间复杂度可以简化到O(n)。

int n;
int top = 0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&x[i]);
while(scanf("%d%d%lld",&a[top],&b[top],&c[top]) == 3)
    top++;
top--;
long long int lastans = 0 - a[top];//解密后为 0 
top--;
anss[top] = lastans;
long long int ans = 0;
for(int i=top;i>0;i--){//倒推 
    ans = (long long int)a[i] * (lastans + 1)*x[lastans] * x[lastans] + (b[i] + 1) * lastans * x[lastans] + c[i] + lastans;
    lastans = (long long int)-ans / ((lastans + 1)*x[lastans] * x[lastans] + lastans * x[lastans] + 1);
    anss[i - 1] = lastans; 
}
for(int i=0;i<=top;i++) printf("%lld\n",anss[i]);
    

 

posted @ 2019-08-01 21:16  Cindy_Chan  阅读(390)  评论(0编辑  收藏  举报