【高精度】【公式】zstuACM 滑雪训练

问题 A: 滑雪训练

时间限制 : 1.000 sec  内存限制 : 128 MB

题目描述
寒假集训结束了,叶老师组织了同学们去参加滑雪。有n个人依次进入滑雪更衣室,准备换衣服滑雪。
更衣室只有一排座位,第1个人进入时,会选择第1个座位坐下。
之后的每个人进入时,他会选择一个离最近的已经坐下的人尽可能远的空位。
如果有多个空位使得离最近的人同样远,则他会从其中随机选取一个。
若有两个人选择的位置相邻,他们就会不满意。
为了让所有人都满意,更衣室至少需要有几个座位呢?
输入
包含一行,仅一个正整数n ,表示前来滑雪的人数。
输出
包含一行,仅一个正整数,表示至少需要的座位数目。
样例输入 Copy

4

样例输出 Copy

8

提示
更衣室只有7个位置时,前3个人会依次选择1,7,4 这3个位置,第4个人无论选哪个空位,都会与其他人相邻。
更衣室有8个位置时,他们依次选取的位置可能是 1 8 4 6 与 1 8 5 3 两种情况,都是合法的。

10% n<=5
另20% n<=10^5
另20% n<=10^18
所有n<=10^1000

思路
注意到 ans=2^q+n,且满足2^q恰好大于等于n-1
推出这样的公式后,只要找到使2^q>=n-1恰好成立的2^q即可

这里给出几组数据
n=1,ans=1;
n=2,ans=3;
n=3,ans=5;
4,8;
5,9;
6,14;
7,15;
8,16;
9,17;
10,26;

AC 代码

//#pragma GCC optimize(2)
//clock_t st=clock();
#include<bits/stdc++.h>
using namespace std;

string prec_plus(string plus_s1,string plus_s2){
	int plus_i1[10100],plus_i2[10100];
	int l1=plus_s1.length(),l2=plus_s2.length();
	string ans="";
	int len=max(l1,l2);
	memset(plus_i1,0,sizeof(plus_i1));
	memset(plus_i2,0,sizeof(plus_i2));
	for(int i=l1-1;i>=0;i--)
		plus_i1[l1-i-1]=plus_s1[i]-'0';
	for(int i=l2-1;i>=0;i--)
		plus_i2[l2-i-1]=plus_s2[i]-'0';
	for(int i=0;i<len;i++){
		plus_i1[i]+=plus_i2[i];
		plus_i1[i+1]+=plus_i1[i]/10;
		plus_i1[i]%=10;
	}
	if(plus_i1[len]!=0) len++;
	while(plus_i1[len-1]==0 and len>1)
		len--;
	for(int i=len-1;i>=0;i--)
		ans=ans+char(plus_i1[i]+'0');
	return ans;
}

string prec_minus(string minus_s1,string minus_s2){ 
	int minus_i1[10100],minus_i2[10100];
	int l1=minus_s1.length(),l2=minus_s2.length();
	string ans="";
	int len=max(l1,l2);
	memset(minus_i1,0,sizeof(minus_i1));
	memset(minus_i2,0,sizeof(minus_i2));
	for(int i=l1-1;i>=0;i--)
		minus_i1[l1-i-1]=minus_s1[i]-'0';
	for(int i=l2-1;i>=0;i--)
		minus_i2[l2-i-1]=minus_s2[i]-'0';
	for(int i=0;i<len;i++){
		minus_i1[i]-=minus_i2[i];
		if(minus_i1[i]<0){
			minus_i1[i]+=10;
			minus_i1[i+1]--;
		}
	}
	while(minus_i1[len-1]==0 and len>1)
		len--;
	for(int i=len-1;i>=0;i--)
		ans=ans+char(minus_i1[i]+'0');
	return ans;
}

string prec_multiply(string multiply_s1,string multiply_s2){ 
	int multiply_i1[1010],multiply_i2[1010],multiply_i3[1010];
	int l1=multiply_s1.length(),l2=multiply_s2.length();
	string ans="";
	int len=(l1+l2);
	memset(multiply_i1,0,sizeof(multiply_i1));
	memset(multiply_i2,0,sizeof(multiply_i2));
	memset(multiply_i3,0,sizeof(multiply_i3));
	for(int i=l1-1;i>=0;i--)
		multiply_i1[l1-i-1]=multiply_s1[i]-'0';
	for(int i=l2-1;i>=0;i--)
		multiply_i2[l2-i-1]=multiply_s2[i]-'0';
	for(int i=0;i<l1;i++){
		for(int j=0;j<l2;j++){
			multiply_i3[i+j]+=multiply_i1[i]*multiply_i2[j];
			multiply_i3[i+j+1]+=multiply_i3[i+j]/10;
			multiply_i3[i+j]%=10;
		}
	}
	while(multiply_i3[len-1]==0 and len>1)
		len--;
	for(int i=len-1;i>=0;i--)
		ans=ans+char(multiply_i3[i]+'0');
	return ans;
}

bool cmp_str(string x1,string x2){//x1>=x2
	if(x1==x2) return true;
	else if(x1.length()!=x2.length()) return x1.length()>x2.length();
	else return x1>x2;
}

//ans=2^q+n,2^q>=n-1

int main(){
	string n;
	cin>>n;
	if(n=="1") {cout<<1;exit(0);}
	string m=prec_minus(n,"1");//m=n-1
	string num="1";//num=2^0=1
	while(!cmp_str(num,m)){
		num=prec_multiply(num,"2");
	}//num=2^q
	string ans=prec_plus(num,n);//ans=num+n
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值