[ZJOI2012]数列 题解 [高精]
[ZJOI2012]数列
Description:
小白和小蓝在一起上数学课,下课后老师留了一道作业,求下面这个数列的通项公式:
\(a_0=0,a_1=1,a_{2i}=a_i,a_{2i+1}=a_i+a_{i+1}\)
小白作为一个数学爱好者,很快就计算出了这个数列的通项公式。于是,小白告诉小蓝自己已经做出来了,但为了防止小蓝抄作业,小白并不想把公式公布出来。于是小白为了向小蓝证明自己的确做出来了此题以达到其炫耀的目的,想出了一个绝妙的方法:即让小蓝说一个正整数 \(n\),小白则说出 \(a_n\) 的值,如果当 \(n\) 很大时小白仍能很快的说出正确答案,这就说明小白的确得到了公式。但这个方法有一个很大的漏洞:小蓝自己不会做,没法验证小白的答案是否正确。作为小蓝的好友,你能帮帮小蓝吗?
Input:
输入文件第一行有且只有一个正整数 \(T\),表示测试数据的组数。
接下来 \(T\) 行,每行一个整数 \(n\)。
Output:
对于每组数据:输出一行一个整数代表 \(a_n\)。
Sample Input:
3
1
3
10
Sample Output:
1
2
3
Hint:
对于 \(20\%\) 的数据,\(1 \leq n \leq 10^{8}\)。
对于 \(50\%\) 的数据,\(1 \leq n \leq 10^{12}\)。
对于 \(100\%\) 的数据,\(1 \leq T \leq 20, 1 \leq n \leq 10^{100}\)。
题目分析:
我们注意到一个神奇的性质:对于两个相邻的两个数 \(i,i+1\) , \(x \times a_i + y \times a_{i+1} = x' \times a_{i/2} + y' \times a_{i/2+1} (i/2 取下整)\)。于是暴力高精即可。
每次记录当前要处理的 \(i\) ,若 \(i\) 为奇数,\(i+1\) 的系数加上 \(i\) 的系数;反之,\(i\) 的系数加上 \(i+1\) 的系数。然后 \(i\) 变成 \(i/2\),直到 \(i\) 等于 \(0\) 时结束,输出 \(i+1\) 对应的系数。初始时 \(i=n\) 。
代码如下(马蜂很丑,不喜勿喷)——
#include<bits/stdc++.h>
#define Tp template<typename T>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define maxn 10005
#define LL long long
using namespace std;
int T,len,len1,len2,ans[maxn],a[maxn],ans1[maxn],ans2[maxn];char s[maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
return ret*f;
}
int main(){
// freopen("data.in","r",stdin);
T=read();while(T--){
scanf("%s",s+1);len=strlen(s+1);len1=max(len1,len2);for(register int i=1;i<=len1;i++) ans1[i]=ans2[i]=0;
ans1[len1=1]=1,len2=0;for(register int i=1;i<=len;i++) a[i]=s[len-i+1]-'0';
while(len>1||a[1]){
if(a[1]&1){
for(register int i=1;i<=len1;i++) ans2[i]+=ans1[i],(ans2[i]>=10)&&(ans2[i]-=10,ans2[i+1]++);
int now=len1+1;while(ans2[now]>=10) ans2[now]-=10,now++,ans2[now]++;if(!ans2[now]) now--;if(now>len2) len2=now;
now=0;for(register int i=len;i;i--) now*=10,now+=a[i],a[i]=(now>>1),now&=1;while(len>1&&!a[len]) len--;
}
else{
for(register int i=1;i<=len2;i++) ans1[i]+=ans2[i],(ans1[i]>=10)&&(ans1[i]-=10,ans1[i+1]++);
int now=len2+1;while(ans1[now]>=10) ans1[now]-=10,now++,ans1[now]++;if(!ans1[now]) now--;if(now>len1) len1=now;
now=0;for(register int i=len;i;i--) now*=10,now+=a[i],a[i]=(now>>1),now&=1;while(len>1&&!a[len]) len--;
}
// for(register int i=len1;i;i--) cout<<ans1[i];cout<<'\n';
// for(register int i=len2;i;i--) cout<<ans2[i];cout<<'\n';
}
for(register int i=len2;i;i--) cout<<ans2[i];puts("");
}
return 0;
}
/*
#include<bits/stdc++.h>
#define Tp template<typename T>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define maxn 10005
#define LL long long
using namespace std;
int T,n,x,y;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
public:
FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x,const char& ch)
{
if (x<0) pc('-'),x=-x; RI ptop=0; while (pt[++ptop]=x%10,x/=10);
while (ptop) pc(pt[ptop--]+48); pc(ch);
}
inline void flush(void)
{
fwrite(Fout,1,Ftop-Fout,stdout);
}
#undef tc
#undef pc
}F;
int main(){
freopen("data.in","r",stdin);
F.read(T);while(T--){F.read(n);x=1,y=0;while(n){if(n&1) y+=x;else x+=y;n>>=1;}F.write(y,'\n');}
return F.flush(),0;
}
*/