[传智杯 #5 初赛] E-梅莉的市场经济学
数据范围无法阻挡我求根公式的步伐QwQ
题意简述
有一个有规律的数列 \(a\):\([0],[0, 1, 0, -1, 0],[0, 1, 2, 1, 0, -1, -2, -1, 0]\dots\),\(q\) 次询问,每次询问求第 \(k\) 项。但是注意,\(k\) 是小于等于 \(4\times 10^{18}\) 的正整数。
题目分析
在 题意简述 里面,我们把由一对中括号括起来的数列称作一段,第 \(i\) 段的长度为 \(S_i\)。那么满足 \(S_i=S_{i-1}+4(i>1)\),且 \(S_1=1\)。满足等差数列性质,公差为 \(4\)。公式法求得,前 \(i\) 段的长度和为:
那么第 \(k\) 项前面有多少段呢?设前面有 \(x\) 段(如果 \(k\) 为一段的末尾,该段也计算,否则不算),\(k\) 是所在段的第 \(y\) 项,那么 \(x\) 是满足 \((2x-1)\cdot x\leq k\) 的最大整数,\(y=k-(2x-1)\cdot x\)。特别的,当 \(y=0\) 时,第 \(k\) 项是所在段的最后一项。
解一元二次不等式 \((2x-1)\cdot x\leq k\),得 \(x\leq\frac {1+\sqrt {1+8k}}{4}\),即 \(x=\lfloor \frac {1+\sqrt {1+8k}}{4} \rfloor\)。知道了 \(x\),\(y\) 自然容易求解。
接着来求第 \(k\) 项的具体值。我们把一段按照单调性分为三段。那么满足:
大功告成!但是别急,数据范围要坑你。我们发现在极端情况 \(k=4\times 10^{18}\) 时,\(1+8k=3.2\times 10^{19}+1\),而 unsigned long long 范围大约是 \([0,1.8\times 10^{19}]\),爆范围了!怎么办呢?小技巧:
即 x=(1+sqrt(8)*sqrt(0.125+k))/4。\(k+0.125\) 不会爆 double,\(8\) 更不会。那么问题迎刃而解了。
代码
#include<bits/stdc++.h>
using namespace std;
long long k,q;
signed main(){
scanf("%lld",&q);
while(q--){
scanf("%lld",&k);
long long x=(1+sqrt(8)*sqrt(0.125+k))/4,y=k-(2*x-1)*x;
if(y==0){printf("0\n");continue;}
if(y<=x+1)printf("%d\n",y-1);
else if(y<=3*x+1)printf("%d\n",x*2+1-y);
else printf("%d\n",y-4*x-1);
}
return 0;
}

浙公网安备 33010602011771号