四道题的难度: 2591<1338<2545<2247
POJ 2591 Set Definition:
这是从discuss里看来的,写的挺好,直接copy,根据我的代码稍有改动(其实也就只改动了一个数字):
题目所给的是个简单的双递归。
我们注意到任何新的元素必然是集合中较小的元素经过两种之一的递推得到的。
这启发我们两个设置标记(比如two,three两个变量):第一个是以方式乘2加1递推,two是没有用过的最小项下标,
第二则表示以乘3加1的方式递推,three是没有用过的最小项下标。开始two =0,three=0,都指向最小的元素0。
然后比较两种递推得到的结果,取较小的放到数组中(这样就得到了一个新的集合元素),并更新相应的下标。
如果相同,只放进去一个,两个下标同时更新。这样可以线性的求出前N个元素。
#include <iostream> #include <stdio.h> #include <map> #include <string.h> #include <algorithm> using namespace std; const long maxn=10000001; long num[maxn]; int two,three; int idx; void init(){ memset(num,0,sizeof(num)); idx=0; num[0]=0; two=three=0; for(int i=1;i<maxn;i++){ if(2*num[two]==3*num[three]){ num[++idx]=2*num[two]+1; two++; three++; } else if(2*num[two]<3*num[three]){ num[++idx]=2*num[two]+1; two++; } else{ num[++idx]=3*num[three]+1; three++; } } } int main() { init(); int n; while(scanf("%d",&n)!=EOF){ printf("%d ",num[n]); } return 0; }
附上discuss里大牛的写法:
#include<stdio.h> #define Min(a, b) ((a)<(b)?(a):(b)) #define N 10000001 long f[N]; int main() { int n,i; int x_2 = 1,x_3 = 1; f[x_2] = 1; f[x_3] = 1; for(i=2; i<=10000000; i++) { f[i] = Min(f[x_2]*2+1, f[x_3]*3+1); if(f[i] == f[x_2]*2+1) x_2++; if(f[i] == f[x_3]*3+1) x_3++; } while(scanf("%d",&n) != EOF) { printf("%ld ",f[n]); } return 0; }
接下来三道题,和上面类似,就不说了,直接附上代码:
POJ 1338 Ugly Numbers
#include <iostream> #include <stdio.h> #include <map> #include <string.h> #include <algorithm> using namespace std; const long maxn=1501; long num[maxn]; int two,three,five; void init(){ memset(num,0,sizeof(num)); num[1]=1; two=three=five=1; for(int i=2;i<maxn;i++){ num[i]=min(2*num[two],min(3*num[three],5*num[five])); if(num[i]==2*num[two]) two++; if(num[i]==3*num[three]) three++; if(num[i]==5*num[five]) five++; } } int main() { int n; init(); while(scanf("%d",&n),n){ printf("%d ",num[n]); } return 0; }
POJ 2545 Hamming Problem
#include <iostream> #include <stdio.h> #include <map> #include <string.h> #include <algorithm> #include <string> /* 本来抱着试一试的态度,再获取n的大小(也就是题目中的i)之后,再建立数组。 本来以为会RE,没想到AC。。。 后来在discuss中看到有人说,在满足output<10^18的情况下,用 2,3,5算出来的最大i大概在10000左右 晕。。。 */ using namespace std; long long p1,p2,p3; long long pp1,pp2,pp3; long long n; int main() { scanf("%I64d%I64d%I64d%I64d",&p1,&p2,&p3,&n); long long *num; num=new long long[n+1]; num[0]=1; pp1=pp2=pp3=0; for(int i=1;i<=n;i++){ num[i]=min(p1*num[pp1],min(p2*num[pp2],p3*num[pp3])); if(num[i]==p1*num[pp1]) pp1++; if(num[i]==p2*num[pp2]) pp2++; if(num[i]==p3*num[pp3]) pp3++; } cout<<num[n]<<endl; return 0; }
POJ 2247 Humble Numbers
#include <iostream> #include <stdio.h> #include <map> #include <string.h> #include <algorithm> #include <string> //刚开始忘记导入了。。。 using namespace std; const long maxn=5845; long long num[maxn]; int two,three,five,seven; map<int,string> form; void init(){ memset(num,0,sizeof(num)); num[1]=1; two=three=five=seven=1; for(int i=2;i<maxn;i++){ num[i]=min(2*num[two],min(3*num[three],min(5*num[five],7*num[seven]))); if(num[i]==2*num[two]) two++; if(num[i]==3*num[three]) three++; if(num[i]==5*num[five]) five++; if(num[i]==7*num[seven]) seven++; } form[0]="th"; form[1]="st"; form[2]="nd"; form[3]="rd"; form[4]="th"; form[5]="th"; form[6]="th"; form[7]="th"; form[8]="th"; form[9]="th"; //注意下面三个。。。 form[11]="th"; form[12]="th"; form[13]="th"; } int main() { int n; init(); while(scanf("%d",&n),n){ int tmp1=n%10,tmp2=n%100; //额额,一开始就只考虑了两位数的情况。。。 if(tmp2==11||tmp2==12||tmp2==13) cout<<"The "<<n<<form[tmp2]<<" humble number is "<<num[n]<<"."<<endl; else if(tmp1==1||tmp1==2||tmp1==3) cout<<"The "<<n<<form[tmp1]<<" humble number is "<<num[n]<<"."<<endl; else{ cout<<"The "<<n<<form[tmp1]<<" humble number is "<<num[n]<<"."<<endl; } } return 0; }