bzoj 2656 数列sequence
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2656
Description
小白和小蓝在一起上数学课,下课后老师留了一道作业,求下面这个数列的通项公式:
小白作为一个数学爱好者,很快就计算出了这个数列的通项公式。于是,小白告诉小蓝自己已经做出来了,但为了防止小蓝抄作业,小白并不想把公式公布出来。于是小白为了向小蓝证明自己的确做出来了此题以达到其炫耀的目的,想出了一个绝妙的方法:即让小蓝说一个正整数N,小白则说出 的值,如果当N很大时小白仍能很快的说出正确答案,这就说明小白的确得到了公式。但这个方法有一个很大的漏洞:小蓝自己不会做,没法验证小白的答案是否正确。作为小蓝的好友,你能帮帮小蓝吗?
Input
输入文件第一行有且只有一个正整数T,表示测试数据的组数。
第2~T+1行,每行一个非负整数N。
Output
输出文件共包含T行。
第i行应包含一个不含多余前缀0的数,它的值应等于An(n为输入数据中第i+1行被读入的整数)
【样例输入】
Sample Input
3
1
3
10
1
3
10
Sample Output
1
2
3
2
3
HINT
T<=20,N<=10^100
原以为,有什么所谓的通项公式,打表列了半天找不出什么通项公式,
一位神犇幽幽的说:这道题属于暴力~~~
只能呵呵了
#include<iostream>
#include<cstring>
#include<cstdio>
#define rad 10000
using namespace std;
int T;
struct data{
int v[105],l;
data(){
v[1]=0;
l=1;
}
void clear(){
memset(v,0,sizeof(v));
l=1;
}
}n,p,q;
char ch[105];
void read(data &x){
data a;
scanf("%s",ch+1);
a.l=strlen(ch+1);
for(int i=1;i<=a.l;i++)
a.v[i]=ch[a.l-i+1]-'0';
for(int i=a.l+1;i<=a.l+4;i++)
a.v[i]=0;
x.l=(a.l-1)/4+1;
for(int i=1;i<=x.l;i++)
{
x.v[i]=0;
for(int k=1;k<=4;k++)
{
x.v[i]=x.v[i]*10+a.v[(i-1)*4+(5-k)];
}
}
}
data operator+(data a,data b){
if(a.l<b.l)swap(a,b);
int t=b.l;
for(int i=1;i<=t;i++)
a.v[i]+=b.v[i];
for(int i=1;i<=t;i++)
if(a.v[i]>=rad)
{
if(i==a.l)
{
a.v[i+1]=0;
a.l++;
}
a.v[i+1]+=a.v[i]/rad;
t=max(t,i+1);
a.v[i]%=rad;
}
return a;
}
data operator+(data a,int p){
data b;
b.v[1]=p;b.l=1;
return a+b;
}
data operator/(data a,int p){
for(int i=1;i<=a.l;i++)
{
if(a.v[i]&1)a.v[i-1]+=rad/p;
a.v[i]/=p;
}
while(!a.v[a.l]&&a.l)a.l--;
return a;
}
void print(data a){
printf("%d",a.v[a.l]);
for(int i=a.l-1;i;i--)
printf("%04d",a.v[i]);
printf("\n");
}
void cal(data x)
{
if(x.l==1&&x.v[1]==1)
{
p=x;q.clear();return;
}
cal((x+1)/2);
if(x.v[1]&1)p=p+q;
else q=p+q;
}
int main()
{
scanf("%d",&T);
while(T--)
{
read(n);
cal(n);
print(p);
}
return 0;
}