codevs 5118 , Wjj的视频2 , 高精度

http://codevs.cn/problem/5118/

题目描述 Description

Wjj又给她的妹子们拍了很多视频。为了拍摄这些视频,并保证视频的清晰度,让每一根毛都能看得清清楚楚,他还特意去买了一张32TB的内存卡。

当Wjj准备用你之前给他写的编号程序给新拍的视频编号时,程序出了错误。

现在,Wjj非常生气,他要你立刻写出正确的程序,并给所有新的视频编好号。


编号的方式和之前相同。第1个视频编号是1;第2、3个视频编号是2,4;第4、5、6个视频编号是5,7,9;接下来四个的编号是10,12,14,16;以此类推。现在Wjj拍摄了n段视频,他要立刻知道第n段视频的编号是多少。


为了尽快看到Wjj拍的视频,你需要写出效率很高的代码来为视频编号,否则就不能欣赏Wjj的作品了。

输入描述 Input Description

输入共一行,一个整数n,表示wjj现在有n段视频

输出描述 Output Description

输出共一行,一个整数,表示第n段视频的编号。

样例输入 Sample Input

【样例输入1】

1


【样例输入2】

4

样例输出 Sample Output

【样例输出1】

1


【样例输出2】

5

数据范围及提示 Data Size & Hint

对于100%的数据,n<10100

和codevs5116题意相同。此题需要用高精度解决。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstring>
#define N 5005
#define D 10000
using namespace std;
struct bignum{
    int len,x[N];
    bignum(int x_=0){x[len=1]=x_;}
    bignum(int x_,int y_){for(register int i=1;i<x_;++i)x[i]=0 ;x[len=x_]=y_;}
    bignum(char *s);
};
 
bignum::bignum(char *s)
{
    int len_s=strlen(s),cnt=0;
    for(int i=len_s-1;i>=0;i-=4)
    {
        int num=0;
        for(register int j=i-3>=0?i-3:0;j<=i;++j) num=num*10+s[j]-'0';
        x[++cnt]=num;
    }
    len=cnt;
}
 
inline bool operator < (const bignum &a,const bignum &b)
{
    if(a.len!=b.len) return a.len<b.len;
    for(register  int i=a.len;i;--i)
        if(a.x[i]!=b.x[i]) return a.x[i]<b.x[i];
    return 0;
}
 
inline bignum operator + (bignum a,bignum b)
{
	bignum c;
	c.len=max(a.len,b.len);
	for(int i=c.len+1;i;--i) c.x[i]=0;
	for(int i=a.len+1;i<=c.len;++i) a.x[i]=0;
	for(int i=b.len+1;i<=c.len;++i) b.x[i]=0;
	for(int i=1;i<=c.len;++i)
		if((c.x[i]+=a.x[i]+b.x[i])>=D) c.x[i]-=D,c.x[i+1]++;
	if(c.x[c.len+1]) c.len++;
	return c;
}

inline bignum operator - (bignum &a,bignum &b)
{
	bignum c;
	c.len=a.len;
	for(int i=c.len;i;--i) c.x[i]=0;
	for(int i=b.len+1;i<=c.len;++i) b.x[i]=0;
	for(int i=1;i<=c.len;++i)
		if((c.x[i]+=a.x[i]-b.x[i])<0) c.x[i]+=D,c.x[i+1]--;
	if(a.len>1&&!a.x[a.len]) a.len--;
	return c;
}

inline bignum operator * (const bignum &a,const bignum &b)
{
    bignum c;
    for(register  int i=a.len+b.len;i;--i) c.x[i]=0;
    for( int i=a.len;i;--i)
        for(register  int j=b.len;j;--j)
        {
            c.x[i+j-1]+=a.x[i]*b.x[j];
            if(c.x[i+j-1]>=1000000000) c.x[i+j]+=c.x[i+j-1]/D,c.x[i+j-1]%=D;
        }
    for(register  int i=1,t=a.len+b.len;i<t;++i)
        if(c.x[i]>=D) c.x[i+1]+=c.x[i]/D,c.x[i]%=D;
    if(!c.x[c.len=a.len+b.len]) c.len--;
    return c;
}

inline void sub(bignum &a)
{
	a.x[1]--;
	for( int j=1;a.x[j]<0;++j)
		a.x[j+1]--,a.x[j]+=D;
	if(a.len>1&&!a.x[a.len]) a.len--;
}

inline bignum sub_r(bignum a)
{
	a.x[1]--;
	for( int j=1;a.x[j]<0;++j)
		a.x[j+1]--,a.x[j]+=D;
	if(a.len>1&&!a.x[a.len]) a.len--;
	return a;
}

inline bignum add(bignum a)
{
	a.x[1]++,a.x[a.len+1]=0;
	for( int j=1;a.x[j]>=D;++j)
		a.x[j+1]++,a.x[j]-=D;
	if(a.x[a.len+1]) a.len++;
	return a;
}

inline bignum div2(bignum a)
{
	for( int j=a.len;j;--j)
	{
		if(a.x[j]&1) a.x[j-1]+=D;
		a.x[j]>>=1;
	}
	if(a.len>1&&!a.x[a.len]) a.len--;
	return a;
}

void output(const bignum &a)
{
    printf("%d",a.x[a.len]);
    for(register int i=a.len-1;i;--i) printf("%04d",a.x[i]);
}

int main()
{
	freopen("oddeven.in","r",stdin);
	freopen("oddeven.out","w",stdout);
	char s[N];
	scanf("%s",s);
	bignum n(s),i(n);
	if(n.len==1&&n.x[1]==1) return puts("1"),0;
	sub(n);

	bignum l(0),r(n);
	while(l<sub_r(r))
	{
		bignum mid=div2(l+r);
		bignum t=div2(mid*add(mid));
		if(n<t) r=mid;
			else l=mid;
	}
	output((n-l)+i);
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值