1. 程式人生 > 實用技巧 >#數位dp,高精度#洛谷 2235 [HNOI2002]Kathy函式

#數位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;
}