潜水多年重新上岸冒个泡……
PS:注意这道题的时间限制为2s(很重要!!!)
不得不说,这确实是一道防AK的好题——见这道题的题解(多年以前的)
相信很多人一看就会觉得这是一道暴力题,因为数据加了密所以根据随机性n^2算法能跑出nlogn,就算不能还有我们很重要的2s时限扛着呢是吧?然而这2s时限并没有什么用处233333什么?我说过这很重要吗这道题确确实实给你搞了若干组暴力会TLE的数据。
我相信你可能会想着分治或高级数据结构,甚至会想到分块来解决这道题。我不知道是否有这样的方法,但是这些显然都不是正解。我们注意到这道题其实有很多提示的地方的。
1.这个方程式
我猜你会想着这很有规律,能不能把它用数学方法转化一下神马的。
但我想说,这……并没有什么很明显的规律(至少我没有看出来)
正是这个没有规律的性质,让我们想到不能用一般方法做这道题
2.对离线的封杀
这其实是欲擒故纵之招,表面上不能离线做,因为没有上一个答案lastans,你根本就不知道a、b、c。但正是这一点误导了许多人,我们总想着用a、b、c算ans,其实没有必要。这道题如果不加密,你好像也没有什么离线的方法去做吧?(<- 一语道破天机)加密就是让你往离线方面想,他其实就是一道离线题。至于为什么,请看下面一条。
3.被加密的end语句
这道题另一个很重要的提示在于,他为什么不采用读入询问个数的方式输入,而是读入到0 0 0结束。而且就算是0 0 0结尾,也不至于把0 0 0给加密了。相信很多人会发现,其实他把最后一个询问的答案告诉你了!我们如果抓住这一条性质,把所有的ans给推出来,不就好了吗?
这看起来很不可思议,但我们还是看看能不能通过最后一个询问和a0、b0、c0,得到倒数第二个询问的答案。
设a=a0+k,b=b0+k,c=c0+k,最后一个答案为i
原始可以化为
(a0+k)*(i+1)*X[i]^2+(b0+k+1)*i*X[i]+c0+k+i=0
将式子拆开得到
(a0*(i+1)*X[i]^2+(b0+1)*i*X[i]+c0+i)+k*((i+1)*X[i]^2+i*X[i]+1)=0
我们发现,左边这一大坨包括a0,b0,c0,i,X[i],全是已知量,记为s
而右边k的系数也全是已知量,记为p
移一下项得到
k=-s/p
这个k便是倒数第二个询问的答案!同理,我们也可以倒着推出所有答案!
这道题虽然十分惊艳,但是我们也是可以找到像这样倒着做的题的,例如下面这道题,就需要倒着做,把删边变成增边,便可以用并茶集来做了!
所以我要给代码了!
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 50005
#define M 500005
#define ll long long
int n,ans[M];
ll ask[M][3],A[N];
int main()
{
//freopen("seq.in","r",stdin);
//freopen("seq.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&A[i]);
int m=1;
while(scanf("%lld%lld%lld",&ask[m][0],&ask[m][1],&ask[m][2])==3)
m++;
m--;
ans[m-1]=-ask[m][0];
for(int i=m-1;i>1;i--)
{
ll a=ask[i][0],b=ask[i][1],c=ask[i][2];
int l=ans[i];
ll s=a*(l+1)*A[l]*A[l]+(b+1)*l*A[l]+c+l;
ll p=l*A[l]+(l+1)*A[l]*A[l]+1;
ans[i-1]=-s/p;
}
for(int i=1;i<m;i++)
printf("%d\n",ans[i]);
}