题目背景
梅莉这个学期选修了经济学。但是主修心理学的她实在不擅长经济领域的分析,为此她时常抱怨自己学不会,想退课。
但是如果现在退掉的话这学期的学分就不够啦,因此她根据“梦中”的经历,“胡诌”了一个简单到不现实的市场模型,并依据这个模型编起了 essay。为了方便地编出图表,她需要写一个程序来查询每个时刻的市场贸易差。
题目描述
市场每一天的贸易差可以视为一个有周期性规律的数列 a: [0],[0,1,0,−1,0],[0,1,2,1,0,−1,−2,−1,0],[0,1,2,3,2,1,0,−1,−2,−3,−2,−1,0]… 具体而言,a 可以被分为无穷段,第 i 段的内容为{0,1,⋯,i,i−1,⋯,0,−1,⋯,−i,−i+1,⋯0}。如下图所示,是将 a 数列内的前一些点绘制在坐标轴上的情况:
现在梅莉对市场发起了 q 次询问,每次她会给定一个 k,希望求出 是多少。
输入格式
- 第一行有一个正整数 q,表示询问次数。
- 接下来 q 行,每行一个正整数 k,描述每次询问。
输出格式
- 输出共 q 行。对于每次询问,输出对应的结果。
-
输入输出样例
输入
9 1 10 100 1000 10000 100000 1000000 10000000 100000000
输出 #1复制
0 1 6 -9 -11 -128 406 1629 5154
题解:
数学题。
由题目描述可以发现每一段的个数为 1 , 5 ,9 , 13 ...,
可以得到第n段的个数为 =1+(n-1)*4,
前n项和 =2*n*n-n
当给定数字k时,应找到k所在的段中,再在该段中寻找结果。
最简单粗暴的方式就是通过1开始枚举,直至找到第一个i使得2*i*i-i>k时,可以得出i-1即为k所在的段,但这样的方法显然时间复杂度太大。
所以换个思路,我们可以从 =2*n*n-n入手,
令=a,解得
再对n取整后可得当前为第n+1段,但是如果n求出来本身就是整数呢(即它为当前段的最后一个)?这时他所对应的即为第n段,于是我们进行如下处理:当算出的n满足2*n*n-n==a时,我们让n--,这样之后可以确保它一定是在第n段的后一段。
由此我们可以知道第n段的范围是到之间,这一部分代码如下:
t=(sqrt(a/2.0+1/16.0)+1/4.0)*1;
if(t*t*2-t==a)t--;
st=2*t*t-t+1;
t++;
en=2*t*t-t;
(st为这一段的第一个位置,en为这一段的最后一个位置)
由此我们已经知道了k所在的位置是在 st 和 en 之间。
再观察图可以发现在第n段中,它总是先从0,开始一个一个增加到n-1之后再开始一个一个减小到 -(n-1)为止,之后再增到0,这时这一段结束。
可以发现每一段的图像都关于 st 和 en 的中点(mid)对称,即
由此可以再定义一个整型变量fu初始值为1,当k>mid时fu=-1。这样可以将正负两部分图像转换为只有正的这一部分上。
同时st和mid之间,又关于直线x=midd对称(midd为st的mid的中点),由此有
由图像可知,时,横坐标与纵坐标的增量均为1,
即,,....从而有
此部分代码为:
long long int i,q=0,st,en,mid,midd,fu=1;
long long int t,l;
t=(sqrt(a/2.0+1/16.0)+1/4.0)*1;
if(t*t*2-t==a)t--;
st=2*t*t-t+1;
t++;
en=2*t*t-t;
mid=(st+en)/2;
if(a>mid)
{
a=(a-mid)+st;
fu=-1;
}
midd=(st+mid)/2;
if(a<midd)cout<<(a-st)*fu<<endl;
else cout<<(mid-a)*fu<<endl;
综上,本题代码如下:
#include<bits/stdc++.h>
using namespace std;
void init(long long int a)
{
long long int i,q=0,st,en,mid,midd,fu=1;
long long int t,l;
t=(sqrt(a/2.0+1/16.0)+1/4.0)*1;
if(t*t*2-t==a)t--;
st=2*t*t-t+1;
t++;
en=2*t*t-t;
mid=(st+en)/2;
if(a>mid)
{
a=(a-mid)+st;
fu=-1;
}
midd=(st+mid)/2;
if(a<midd)cout<<(a-st)*fu<<endl;
else cout<<(mid-a)*fu<<endl;
}
int main()
{
int n;
long long int a;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a;
if(a==1){
cout<<"0"<<endl;
}else init(a);
}
return 0;
}
水平有限,如有错误,欢迎指出!