一行兩個整數n,m(1<=n,m<10^100)。
一行表示答案
2 1
2
高精度+DP+神奇的思路~
花了我六十……好心疼啊QAQ
我們用f[i][j]表示j個圓盤,用i步的方案數,那麼
當i在第三根柱子上時,=f[i-1][j];
其餘情況,我們把所有小於它的圓盤移到1或2柱子上,移動i後,再用(2^(i-1)-1)步移回來,=f[i-1][j-2^(i-1)]。
所以f[i][j]=f[i-1][j]+f[i-1][j-2^(i-1)]*2。
觀察到n<=10^100,n趨於無窮大,這時i和i-1近似相等,我們發現第一維可以忽略,f[j]=2^(n中1的個數)。
所以我們用高精度求一下這個值就好了……
要注意特判0的情況。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,a[1001],f[1001],tot,cnt;
char s[1001],s1[1001];
int cal()
{
int tot=0;
for(int i=0;i<n;i++) tot=tot*10+s1[i]-'0';
return tot;
}
int main()
{
scanf("%s%s",s1,s);
n=strlen(s);
for(int i=0;i<n;i++) a[n-i]=s[i]-'0';
f[1]=tot=1;
for(;n>1 || a[1];cnt++)
{
if(a[1]&1)
{
for(int i=1;i<=tot;i++) f[i]*=2;
for(int i=1;i<=tot;i++) if(f[i]>9) f[i+1]++,f[i]-=10;
if(f[tot+1]) tot++;
}
for(int i=n,z=0;i;i--) z=z*10+a[i],a[i]=z>>1,z&=1;
if(!a[n]) n--;
}
n=strlen(s1);
if(n<=3 && cnt>cal()) puts("0");
else for(int i=tot;i;i--) printf("%c",f[i]+'0');
return 0;
}