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;
}
posted @ 2022-07-20 20:11  lzylzy/kk  阅读(36)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end