大年夜的写代码果然状态非常之差...感觉特别困,连个高精度都折腾了我好久。还是刘汝佳《训练指南》里的一道例题,解题思路其实也差不多,但是想对书里面的内容再讲讲。其中d[i]是代表i个火柴棒恰好能构成的正整数数目(不包含整数0),然后有点类似于动态规划的做法,通过已知的d[]求出剩下的d[]。
不过仔细想来貌似有点问题。例如已知d[j],那么d[j+num[0]]+=d[j].那么新加的数字0是不是应该也有好几种排列方式呢?例如d[j]中有一个数字123,那么d[j+num[0]]是不是应该有1230,1203,1023...等等各种方式呢?其实不是的d[j+num[0]]+=d[j]这个式子其实都是在数的末尾添加新数字的。123新增一个0就是1230,而1203则是120新加一个3完成的。所以,!(i==0&&j==0)就可以理解了。第一个数字不能是0,否则会产生前置0的问题。至于那个整数0,在N>=6时,每个答案都要加上1。
头有点晕,哈哈哈,写得可能不是很清楚,具体还是参考代码吧!另:用string还是会超时,可能是由于频繁的内存分配问题....
#include <iostream> #include <string> #include <cstdio> #include <algorithm> #define MAX 2000+5 #define MAXL 1000 using namespace std; char d[MAX][MAXL],ans[MAX][MAXL];//d[i]为恰好用i根火柴棍能完成的正整数,ans[i]为最后的解答 int dlen[MAX],alen[MAX];//dlen[i]对应字符串d[i]的长度,alen同理对应ans int num[10]={6,2,5,5,4,5,6,3,7,6};//10个数字对应的火柴棍数 void add(int&,int,char*,const char*); int main() { d[0][0]='1',dlen[0]=1; d[1][0]='0',dlen[1]=1;//这里必须要初始化,否则按照下述高精度方式,ans[i]可能会产生空 for(int i=0;i<MAX;++i){ for(int j=0;j<10;++j){ if(!(i==0&&j==0)&&i+num[j]<MAX) add(dlen[i+num[j]],dlen[i],d[i+num[j]],d[i]); } } for(int i=1;i<MAX;++i){ for(int j=1;j<=i;++j) add(alen[i],dlen[j],ans[i],d[j]); if(i>=6) add(alen[i],1,ans[i],"1");//火柴棍数大于6,结果要加1 } int N; while(cin>>N){ int pos; for(pos=alen[N]-1;pos>=0;--pos) cout<<ans[N][pos]; cout<<endl; } return 0; } void add(int& la,int lb,char* a,const char* b)//高精度运算 { int len; len=max(la,lb); int sum,overflow=0; for(int i=0;i<len;++i){ if(lb<=i){//被加的字符长度不足 sum=a[i]-'0'+overflow; } else{ if(la<=i){a[i]='0';++la;}//加的字符串长度不足,且长度值需修改 sum=a[i]-'0'+b[i]-'0'+overflow; } a[i]=sum%10+'0'; overflow=sum/10; } if(overflow){//还有进位 a[la++]=overflow+'0'; } return; }
原文:http://blog.csdn.net/u011915301/article/details/43878471