UVA12105 越大越好 Bigger is Better
一些trick
一个显然的dp是 用了i个火柴 余数是j 拼出来最大数是多少
但发现n是100 就是说最大数有五十位左右 int128也存不下
所以转换思路,考虑按位贪心,从最高位开始放,放尽量大的数
具体的,我们设f[i][j]表示前i位,余数是j,最少要用多少根火柴
预处理f数组,从最大的f[i][0]<=n的位置开始计算答案即可
也是dp的一种思路~
#include<bits/stdc++.h>
using namespace std;
const int inf=0x7fffffff;
#define ll long long
int n,m;
int f[109][3009];
int ret[10]={6,2,5,5,4,5,6,3,7,6};
int ksm(int a,int b,int p)
{
int res=1,base=a;
while(b)
{
if(b&1)res=res*base%p;
b>>=1;
base=base*base%p;
}
return res;
}
signed main()
{
for(int T=1;;T++)
{
scanf("%d",&n);
if(!n)break;
scanf("%d",&m);
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for(int i=0;i<=n;i++)
{
int k1=ksm(10,i,m);
for(int j=0;j<m;j++)
{
if(f[i][j]==0x3f3f3f3f)continue;
for(int p=0;p<=9;p++)
{
int t=k1*p%m;
int to=(j+t)%m;
f[i+1][to]=min(f[i+1][to],f[i][j]+ret[p]);
// printf("%d %d %d\n",i+1,to,f[i+1][to]);
}
}//cout<<i<<endl;
}
printf("Case %d: ",T);
int s=n,ok=0,now=0,st=n;
for(st=n;st>=0;st--)if(f[st][0]<=n)break;
for(int i=st;i>=1;i--)
{
int t=ksm(10,i-1,m);
for(int j=9;j>=0;j--)
{
if(f[i-1][(m-(now+t*j)%m)%m]>s-ret[j])
{
continue;
}
s-=ret[j];now+=t*j;now%=m;
ok=1;
printf("%d",j);break;
}
}
if(!ok)printf("-1");
putchar('\n');
}
return 0;
}