#数位dp,高精度#洛谷 2235 [HNOI2002]Kathy函数
分析
首先这个\(f\)函数其实求的是二进制下的回文数,简单证明一下
设\(n\)在二进制下的回文数为\(n'\),第一二条显然
第三条\(f(2n)=f(n)\Rightarrow \overline {0} n'=n'\),很好证明
第四条\(f(4n+1)=2f(2n+1)-f(n)\Rightarrow \overline {10}n'=\overline{1}n'\overline{0}-n'=\overline{10}n'\)
第五条
\[f(4n+3)=3f(2n+1)-2f(n)=2(2f(2n+1)-f(n))-f(2n+1)=2f(4n+1)-f(2n+1)
\]
\[\Rightarrow\overline{11}n'=\overline{10}n'\overline{0}-\overline{1}n'=\overline{11}n'
\]
得证,对于位数小于\(n\)的位数答案,易求
对于位数等于\(n\)的位数的答案,特判\(n\)是否为回文数
给出一个伪代码
inline bool mxcheck(lll m,lll len){
rr int j=len/2,i=len-j-1;
for (;i>=0&&j<len;--i,++j){
if (((m>>i)&1)>((m>>j)&1)) return 1;
if (((m>>i)&1)<((m>>j)&1)) return 0;
}
return 1;
}
signed main(){
scanf("%lld",&m);
for (len=1,n=1;n<m;++len,n=n<<1|1)
ans+=1ll<<((len-1)/2);
ans+=(m&(n>>1))>>(len>>1);
if (mxcheck(m,len)) ++ans;
printf("%lld\n",ans);
}
改成高精度就可以A了
代码
#include <cstdio>
#include <cctype>
#define rr register
#define mod 1000000000
using namespace std;
int len,Ans,a[351],ans[351],Q[101],Qlen;
inline void add_one(int *a,int now,int &len){//在二进制的某一位加1
for (;a[now];++now) a[now]=0; a[now]=1;
if (now>=len) len=now+1;
}
inline bool mxcheck(){
rr int j=len/2,i=len-j-1;
for (;i>=0&&j<len;--i,++j)
if (a[i]!=a[j]) return a[i]>a[j];
return 1;
}
inline void innput(){
rr char c=getchar();
for (;!isdigit(c);c=getchar());
for (;isdigit(c);c=getchar()){
rr int w=c^48,t=0;
if (len){
len+=3;
for (rr int j=len-1;~j;--j){
a[j]=0;
if (j>=3&&a[j-3]) add_one(a,j,len);
if (j>=1&&a[j-1]) add_one(a,j,len);
}
}
for (;w;w>>=1,++t) if (w&1) add_one(a,t,len);
}
}
signed main(){
innput();
for (rr int i=0;i<len-1;++i)
add_one(ans,i>>1,Ans);
for (rr int i=len/2,j=0;i<len-1;++i,++j)
if (a[i]) add_one(ans,j,Ans);
if (mxcheck()) add_one(ans,0,Ans);
for (rr int i=Ans-1;~i;--i){//将二进制转换为十进制
rr int g=0;
for (rr int j=0;j<Qlen;++j){
rr int s=Q[j]*2+g;
g=s/mod,Q[j]=s%mod;
}
if (g) Q[Qlen++]=g;
g=ans[i]; rr int t=0;
for (;g;++t) g=(++Q[t])/mod;
if (t>Qlen) Qlen=t;
}
printf("%d",Q[Qlen-1]);
for (rr int i=Qlen-2;~i;--i) printf("%09d",Q[i]);
return 0;
}