BZOJ 2656 [Zjoi2012] 数列(sequence)

Description

   小白和小蓝在一起上数学课,下课后老师留了一道作业,求下面这个数列的通项公式:

   小白作为一个数学爱好者,很快就计算出了这个数列的通项公式。于是,小白告诉小蓝自己已经做出来了,但为了防止小蓝抄作业,小白并不想把公式公布出来。于是小白为了向小蓝证明自己的确做出来了此题以达到其炫耀的目的,想出了一个绝妙的方法:即让小蓝说一个正整数N,小白则说出的值,如果当N很大时小白仍能很快的说出正确答案,这就说明小白的确得到了公式。但这个方法有一个很大的漏洞:小蓝自己不会做,没法验证小白的答案是否正确。作为小蓝的好友,你能帮帮小蓝吗?

Input

      输入文件第一行有且只有一个正整数T,表示测试数据的组数。

     2T+1行,每行一个非负整数N

Output

      输出文件共包含T行。

i行应包含一个不含多余前缀0的数,它的值应等于An(n为输入数据中第i+1行被读入的整数)

【样例输入】

Sample Input

3

1

3

10

Sample Output

1
2
3


HINT

T<=20,N<=10^100

Source

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

二叉树+高精度~

刚开始用十进制写的,结果T了,时限2s跑了2.9s……然后学黄学长的改成了10000进制……太神了……

输出的时候用%04d,可以补全前导0。


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define rad 10000

int t,c[105],len;
char s[105];

struct node{
	int a[105],len;
	node(){
		len=1;a[1]=0;
	}
	void clear()
	{
		memset(a,0,sizeof(a));len=1;
	}
}n,p,q;

node operator + (node u,node v)
{
	if(u.len<v.len) swap(u,v);
	int w=v.len;
	for(int i=1;i<=w;i++) u.a[i]+=v.a[i];
	for(int i=1;i<=w;i++)
	  if(u.a[i]>=rad)
	  {
	  	if(i==u.len)
	  	{
	  		u.a[i+1]=0;u.len++;
		}
		u.a[i+1]+=u.a[i]/rad;
		u.a[i]%=rad;
		w=max(w,i+1);
	  }
	return u;
}

node operator + (node u,int v)
{
	node b;
	b.len=1;b.a[1]=v;
	return u+b;
}

node operator / (node u,int v)
{
	for(int i=u.len;i;i--)
	{
		u.a[i-1]+=(u.a[i]%v)*rad;u.a[i]/=v;
	}
	while(!u.a[u.len] && u.len) u.len--;u.a[0]=0;
	return u;
}

void findd(node u)
{
	if(u.len==1 && u.a[1]==1)
	{
		p=u;q.clear();return;
	}
	findd((u+1)/2);
	if(u.a[1]&1) p=q+p;
	else q=p+q;
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%s",s);
		len=strlen(s);
		for(int i=1;i<=len;i++) c[i]=s[len-i]-'0';
		for(int i=1;i<=4;i++) c[i+len]=0;
		n.len=(len-1)/4+1;
		for(int i=1;i<=n.len;i++)
		{
			n.a[i]=0;
			for(int j=1;j<=4;j++) n.a[i]=n.a[i]*10+c[(i-1)*4+5-j];
		}
		findd(n);
		printf("%d",p.a[p.len]);
		for(int i=p.len-1;i;i--) printf("%04d",p.a[i]);printf("\n");
	}
	return 0;
}


原来的程序,T掉了。


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

int t;
char s[101];

struct node{
	int a[1001],len;
}n,c[2];

node cheng(node u,int v)
{
	for(int i=1;i<=u.len;i++) u.a[i]*=v;
	for(int i=1;i<=u.len;i++)
	{
		u.a[i+1]+=u.a[i]/10;
		u.a[i]%=10;
	}
	if(u.a[u.len]) u.len++;
	return u;
}

node chu(node u,int v)
{
	for(int i=u.len;i;i--)
	{
		u.a[i-1]+=(u.a[i]%v)*10;
		u.a[i]/=v;
	}
	u.a[0]=0;
	while(!u.a[u.len]) u.len--;
	return u;
}

node jia(node u,node v)
{
	if(u.len<v.len) swap(u,v);
	for(int i=1;i<=u.len;i++)
	{
		u.a[i]+=v.a[i];
		u.a[i+1]+=u.a[i]/10;
		u.a[i]%=10;
	}
	if(u.a[u.len+1]) u.len++;
	return u;
}

node jiac(node u,int v)
{
	u.a[1]+=v;
	for(int i=1;i<=u.len;i++)
	  if(u.a[i]<10) break;
	  else
	  {
	  	u.a[i+1]++;u.a[i]%=10;
	  }
	if(u.a[u.len+1]) u.len++;
	return u;
}

bool operator == (node u,node v)
{
	if(u.len!=v.len) return 0;
	for(int i=1;i<=u.len;i++) if(u.a[i]!=v.a[i]) return 0;
	return 1;
}

node cal(node u)
{
	if(u==c[0]) return c[0];
	if(u==c[1]) return c[1];
	if(u==c[2]) return c[2];
	if(u.a[1]%2)
	{
		node l=chu(u,2),r=jiac(l,1);
		return jia(cal(l),cal(r));
	}
	return cal(chu(u,2));
}

int main()
{
	scanf("%d",&t);
	c[0].len=c[1].len=c[2].len=1;c[0].a[1]=0;c[1].a[1]=c[2].a[1]=1;
	while(t--)
	{
		scanf("%s",s);
		n.len=strlen(s);int now=0;
		for(int i=n.len-1;i>=0;i--) n.a[n.len-i]=s[i]-'0';
		node ans=cal(n);
		while(!ans.a[ans.len]) ans.len--;
		for(int i=ans.len;i;i--) printf("%d",ans.a[i]);printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值