天平 数学+DP
【问题描述】
大牛最近正在为自己的体重而苦恼,他想称量自己的体重。于是,他找来一个天平与许
多砝码。
砝码的重量均是 n 的幂次,n^1、n^2、n^3、n^4、n^5 的......大牛想知道至少要多少个
砝码才可以称出他的重量 m。注意砝码可以放左边,也可以放右边。
【输入格式】
第一行一个正整数 m,表示大牛的重量;
第二行一个正整数 n,表示砝码重量幂次的底;
【输出格式】
一个整数表示最少所需的砝码数。
【样例输入】
99
10
【样例输出】
2
【数据范围】
对于 30%的数据点,m <= 2^63 - 1
对于 100%的数据点,0 <= m <= 10^10000, 0 < n <= 10000
首先我们很容易想到把m化成n进制数来考虑。
所以我们先用高进度除法把m化成n进制数,然后因为可以放左右边,所以到了当前位,我们可以选择放x个砝码,也可以选择放n-x个砝码,然后下一位加1。
考虑到当前选择没有后效性,我们于是考虑在每一位上DP。
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define ll long long #define il inline #define db double #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) using namespace std; int n; char mm[100045]; int a[100045],b[100045]; int yushu[100045],yu; int len; bool flag; il void get() { int rest=a[0]; int now=1; int cnt=0; while(now<=len-1) { rest=rest*10+a[now]; if(rest>=n) { b[cnt++]=rest/n; rest=rest%n; } else b[cnt++]=0; now++; } yushu[++yu]=rest; for(int i=0;i<cnt/2;i++) swap(b[i],b[cnt-i-1]); while(b[cnt-1]==0) cnt--; for(int i=0;i<cnt/2;i++) swap(b[i],b[cnt-i-1]); if(cnt<=0) flag=1; for(int i=0;i<cnt;i++) a[i]=b[i]; len=cnt; } ll f[100045][2]; int main() { freopen("balance.in","r",stdin); freopen("balance.out","w",stdout); scanf("%s",mm); len=strlen(mm); for(int i=0;i<len;i++) a[i]=mm[i]-'0'; cin>>n; if(n==1) { for(int i=0;i<len;i++) printf("%c",mm[i]); return 0; } while(flag==0) get(); f[0][0]=0; f[0][1]=1; //for(int i=1;i<=yu;i++) // printf("%d\n",yushu[i]); //cout<<endl; for(int i=1;i<=yu;i++) { f[i][0]=min(f[i-1][0]+yushu[i],f[i-1][1]+yushu[i]+1);//直接拿出 f[i][1]=min(f[i-1][0]+n-yushu[i],f[i-1][1]+n-yushu[i]-1);//反向拿出 } printf("%lld\n",min(f[yu][0],f[yu][1]+1)); return 0; }
PEACE