数列

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.

 

题目所谓的防离线就是让你倒着做;

最后一个lastans在数据中已知;

只要倒着继续求前面的lastans即可;

然而还是正解还是离线算法。。。。

方法一:把题目中 加密的 a=a0+lastans;b=b0+lastans;c=c0+lastans;a0,b0,c0从公式中提出;

因为当前的i和xi已知 所以 a0*i*xi*xi+(b0+1)*i*xi+i+c0是常数 只要把其移到右边 除去lastans的系数就得出上一个的答案o(n);

#include <queue>
#include <stack>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
long long n,m,x[500005],a[500005],b[500005],c[500005],ans[500005];
int main(){
	//freopen("seq.in","r",stdin);
	//freopen("seq.out","w",stdout);
	scanf("%lld",&n);
	for (int i=1;i<=n;i++) scanf("%lld",&x[i]);
	for (m++;~scanf("%lld%lld%lld",&a[m],&b[m],&c[m]);m++);
	ans[m-2]=-a[--m];
	for (int i=m-1;i;i--){
		if (i==371614){
			int tag=0;
		}
		long long X=-(a[i]*x[ans[i]]*x[ans[i]]*(ans[i]+1)+(b[i]+1)*x[ans[i]]*ans[i]+c[i]+ans[i]);
		long long Y=(x[ans[i]]*x[ans[i]]*(ans[i]+1)+x[ans[i]]*ans[i]+1);
		ans[i-1]=X/Y;
	}
	for (int i=1;i<m;i++) printf("%lld\n",ans[i]);
	//fclose(stdin); fclose(stdout);
	return 0;
}

  

方法二 :考试的时候胡思乱想 发现了当a b c同时增加整体值肯定递增;

举个例子 a b c同时加1 那么 等于加上 (i+1)xi*xi+xi*i+1;很明显 (i+1)*xi*xi+1>xi*i;

满足了单调性 那么就可以二分lastans了;将所有值代入公式进行check();简单又暴力 时间效率差一些o(nlogn);

#include<cstdio>
#include<iostream>
using namespace std;
int xx[500110];
long long a[501010],b[501010],c[501010],ans[500100];
int t,i,j,k,l,r,mid,n;
long long a1,b1,c1,d;
bool check()
{
	return (long long)a[i]*a1*(xx[d]*xx[d])+(b[i]+1)*b1*xx[d]+c[i]+ans[i]>=0? true:false;
}
int main()
{
//	freopen("xx.in","r",stdin);
	scanf("%d",&n);
	for(i=1;i<=n;++i)
	scanf("%d",&xx[i]);
	t=1;
	while(~scanf("%lld%lld%lld",&a[t],&b[t],&c[t]))
	t++;
	t-=2;ans[t]=-a[t+1];
	for(i=t;i>=2;--i)
	{
		l=1;r=n;
		a1=ans[i]+1;b1=ans[i];d=ans[i];
		while(l<=r)
		{
			mid=(l+r)>>1;
			a[i]+=mid;b[i]+=mid;c[i]+=mid;
			if(check())r=mid-1,ans[i-1]=mid;
			else l=mid+1;
			a[i]-=mid;b[i]-=mid;c[i]-=mid;
		}
	}
	for(i=1;;++i)
	if(ans[i])printf("%lld\n",ans[i]);
	else break;
}

  

posted @ 2016-11-04 21:51  peter863  阅读(201)  评论(0编辑  收藏  举报