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

121 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

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

题目背景

梅莉这个学期选修了经济学。但是主修心理学的她实在不擅长经济领域的分析,为此她时常抱怨自己学不会,想退课。

但是如果现在退掉的话这学期的学分就不够啦,因此她根据“梦中”的经历,“胡诌”了一个简单到不现实的市场模型,并依据这个模型编起了 essay。为了方便地编出图表,她需要写一个程序来查询每个时刻的市场贸易差。

题目描述

市场每一天的贸易差可以视为一个有周期性规律的数列 aa[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]\color{red}[0],\color{blue}[0,\allowbreak 1,\allowbreak 0,\allowbreak -1,\allowbreak 0],\color{red}[0,\allowbreak 1,\allowbreak 2,\allowbreak 1,\allowbreak 0,\allowbreak -1,\allowbreak -2,\allowbreak -1,\allowbreak 0],\allowbreak \color{blue}[0,\allowbreak 1,\allowbreak 2,\allowbreak 3,\allowbreak 2,\allowbreak 1,\allowbreak 0,\allowbreak -1,\allowbreak -2,\allowbreak -3,\allowbreak -2,\allowbreak -1,\allowbreak 0]\dots 具体而言,aa 可以被分为无穷段,第 ii 段的内容为 {0,1,,i,i1,,0,1,,i,i+1,0}\{0,\allowbreak 1,\allowbreak \cdots,\allowbreak i,\allowbreak i-1,\allowbreak \cdots,0,\allowbreak -1,\allowbreak \cdots,\allowbreak -i,\allowbreak -i+1,\allowbreak \cdots 0\}。如下图所示,是将 aa 数列内的前一些点绘制在坐标轴上的情况:

现在梅莉对市场发起了 qq 次询问,每次她会给定一个 kk,希望求出 aka_k 是多少。

输入格式

  • 第一行有一个正整数 qq,表示询问次数。
  • 接下来 qq 行,每行一个正整数 kk,描述每次询问。

输出格式

  • 输出共 qq 行。对于每次询问,输出对应的结果。

样例 #1

样例输入 #1

9
1
10
100
1000
10000
100000
1000000
10000000
100000000

样例输出 #1

0
1
6
-9
-11
-128
406
1629
5154

提示

对于所有数据,1q1051 \leq q \leq 10^51k4×10181 \leq k \leq 4\times 10^{18}

分析

这题乍一看很复杂,其实很简单,但是当我看了一眼kk的范围,不禁还是啧了一下,看来不能用数组去存数,浅浅看一下,可以发现,这个是有规律的数学题,其实我们可以把这个数列分成不同的组,每一组可以发现就是4n34n-3个数字,于是前nn组一共有n(2n1)n*(2n-1)个数,很显然,每一组内部也是有规律的,规律就是先上升再下降,然后变成负数下降,再上升到00,于是我们只需要确定每个kk的组别就行了,很简单,用二分可以判断出每个k的组别,然后后面的规律可以用ifif语句很容易的找出。

代码

#include <iostream>
#include <string> 
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <cstring>
#include <stack> 
#include <cmath>
#include <algorithm>
#define int long long
using namespace std;
const int N=201000;
int f(int x){
	return x*2*x-x;
}
signed main(){
	int t;
	cin>>t;
	while(t--){
		int q;
		cin>>q;
		int l=1,r=2e9+10;
		while(l<r){
			int mid=l+r>>1;
			if(f(mid)<q){
				l=mid+1;
			}
			else r=mid;
		}
		//cout<<l<<endl;
		int g=l;
		//cout<<g<<endl;
		int loc=f(g)-q;
		if(loc==0) cout<<0<<endl;
		else{
			//int sign=g-1;
			
			loc=q-f(g-1);
			//cout<<loc<<endl;
			if(loc>=1 && loc <=g) cout<<loc-1<<endl;
			else if(loc>g && loc<=2*g-1) cout<<2*g-1-loc<<endl;
			else if(loc>=2*g && loc<=3*g-2) cout<<2*g-1-loc<<endl;
			else if(loc>=3*g-1 && loc<=4*g-4)cout<<loc-(4*g-3)<<endl;
		}
		
		//if(q)
	}
	return 0;
}

希望能帮助到大家(QAQQAQ)!