【题目链接】https://cn.vjudge.net/contest/173912#problem/I
【题意】 就是说0~9每个数字都可以用火柴拼出来,现在告诉你一个数字--火柴数,让你求最多可以拼出多少种数字,不同的值代表不同的组合。
【分析】 动态规划题,但是组出来的数字可能非常大,所以就要用高精度加法,dp部分倒是不难,设dp[i] 表示第i根火柴时组成的最大方案数,这里要明白,i-1根火柴能拼出的数i根火柴也一定能拼出来,所以递推公式就出来了:
dp[i]+=dp[i-1],重点在高精度写法上,这儿比较容易错,不过上次就遇到一个比较好的高精度写法---高精度类,即把高精度算法封装起来当成类来用,这样就解释一个现成的模板了,下面有代码。
【AC代码】
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=2001;
int m,n;
int vis[10]={6,2,5,5,4,5,6,3,7,6}; //组成每个数组需要的火柴数打表
struct node //高精度加法类模板
{
int a[N],len;
node()
{
memset(a,0,sizeof(a));
len=0;
}
node(int x)
{
a[0]=x;
len=1;
}
node operator + (const node& n) const
{
node ss;
ss.len=max(len,n.len);
for(int i=0;i<ss.len;++i)
{
ss.a[i]+=a[i]+n.a[i];
ss.a[i+1]=ss.a[i]/10;
ss.a[i]%=10;
}
if(ss.a[ss.len]>0) ss.len++;
return ss;
}
node operator += (const node& n)
{
*this=*this+n;
return *this;
}
void print()
{
if(len==0) printf("0\n");
else{
for(int i=len-1;i>=0;--i) //逆序输出数字
printf("%d",a[i]);
printf("\n");
}
}
}dp[N];
int main()
{
dp[0]=node(1);
for(int i=0;i<N;++i)//遍历i根火柴
for(int j=0;j<10;++j)//i根火柴组成的数字加上vis[j]根火柴组成的数字
if(i+vis[j]<N && (i||j))//如果能组成并且没有前导0
dp[i+vis[j]]+=dp[i];
dp[6]+=node(1); //特判 6根火柴可以组成一个0
for(int i=2;i<N;++i)//i-1根火柴能组成的数字 i根火柴也一定能组成,
{
dp[i]+=dp[i-1];
}
while(~scanf("%d",&m))
dp[m].print();
return 0;
}