【NOIP模拟赛】 思维+离线+递推 数列(好题)


    潜水多年重新上岸冒个泡……

    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]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值