[传智杯 #5 初赛] E-梅莉的市场经济学

数据范围无法阻挡我求根公式的步伐QwQ


题意简述

有一个有规律的数列 a[0],[0,1,0,1,0],[0,1,2,1,0,1,2,1,0]q 次询问,每次询问求第 k 项。但是注意,k 是小于等于 4×1018 的正整数。

题目分析

题意简述 里面,我们把由一对中括号括起来的数列称作一段,第 i 段的长度为 Si。那么满足 Si=Si1+4(i>1),且 S1=1。满足等差数列性质,公差为 4。公式法求得,前 i 段的长度和为:

[1+1+4(i1)]i2=(2i1)i

那么第 k 项前面有多少段呢?设前面有 x 段(如果 k 为一段的末尾,该段也计算,否则不算),k 是所在段的第 y 项,那么 x 是满足 (2x1)xk 的最大整数,y=k(2x1)x。特别的,当 y=0 时,第 k 项是所在段的最后一项。

解一元二次不等式 (2x1)xk,得 x1+1+8k4,即 x=1+1+8k4。知道了 xy 自然容易求解。

接着来求第 k 项的具体值。我们把一段按照单调性分为三段。那么满足:

ak={0,y=0,y1,0<yx+1,2x+1y,x+1<y3x+1,y4x1,otherwise.

大功告成!但是别急,数据范围要坑你。我们发现在极端情况 k=4×1018 时,1+8k=3.2×1019+1,而 unsigned long long 范围大约是 [0,1.8×1019],爆范围了!怎么办呢?小技巧:

8k+1=8k+0.125

x=(1+sqrt(8)*sqrt(0.125+k))/4k+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;
}
posted @   robinyqc  阅读(24)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示