Project Euler 21-25题

来源:互联网 发布:舒缦水暖床垫淘宝网 编辑:程序博客网 时间:2024/06/05 07:49

第21题

这里写图片描述
题目来源ProjectEuler

这个题定义了一个函数d(x)=divisori,其中divisorix的因子且!=x
求小于10,000的所有满足d(d(a))==aa的和。
首先求所有数不为本身的因子的和。如果一个数一个数去分解,复杂度将会是O(nn)的。但是有一个O(nlogn)的算法,枚举1至n的所有数i(其实枚举到n2就可以),将[2i,n]里所有i的倍数的标记都加i
然后枚举1至n的所有数i,判断d(d(i))==i是否成立,若成立则加入答案。

int d[10001];int main(){    int n=10000;    for (int i=1;i<=n;i++){        for (int j=i*2;j<=n;j+=i){            d[j]+=i;        }    }    int ans=0;    for (int i=1;i<=n;i++){        if (d[i]!=i&&d[i]<=n&&d[d[i]]==i){            ans+=i;        }    }    cout<<ans<<endl;    return 0;}



第22题

这里写图片描述
题目来源ProjectEuler
题中txt地址:https://projecteuler.net/project/resources/p022_names.txt

这个题是给你超过5000个名字(其实是5163个),将所有名字按字典序排序后,求orderiscorei,其中scorei定义为名字中每个字母在26个字母表中的位置。

这道题最最坑爹的地方是,题中没有说明orderi是从0开始计数的

我原来想过使用hash的方法用整型表示每个名字的字典序的,但是没找到很好的hash函数。结果就只能每次直接比较名字的字典序,复杂度变成了O(lengthnlogn)的了。建议使用编辑器的替换功能将所有的引号和逗号替换成’\n’

struct Name{    char s[20];    int sum;    Name(){sum=0;}}name[10500];bool cmp(Name a,Name b){return strcmp(a.s,b.s)<0;}int main(){    int cnt=-1;    freopen("in.txt","r",stdin);    while(scanf("%s",name[++cnt].s)!=EOF){        for (int i=0;name[cnt].s[i];i++){            name[cnt].sum+=name[cnt].s[i]-'A'+1;        }    }    sort(name,name+cnt+1,cmp);    long long ans=0;    for (int i=0;i<=cnt;i++){        ans+=i*name[i].sum;    }    cout<<ans<<endl;    return 0;}



第23题

这里写图片描述
题目来源ProjectEuler

定义 abundant number为所有非己因数和大于自己的数。
题目中告知大于28213的所有数都可以表示成两个abundant number的和。
问所有正数中不能被表示成两个abundant number的数的和。

使用类似21题的做法,求出小于28213的所有数的非己因数和,将非己因数和大于自身的数加入到vector里面,做一个O(n2)的处理,求出这些数两两组合的和,打上标记。最后将所有未标记的数加起来。

int num[30000];vector<int> v;int isable[30000];int main(){    int n=28123;    memset(num,0,sizeof(num));    memset(isable,0,sizeof(num));    for (int i=1;i<=n;i++){        for (int j=i*2;j<=n;j+=i){            num[j]+=i;        }    }    for (int i=1;i<=n;i++){        if (num[i]>i)   {            v.push_back(i);        }    }    for (int i=0,maxn=v.size();i<maxn;i++){        for (int j=i;j<maxn&&v[i]+v[j]<=n;j++){            isable[v[i]+v[j]]=1;        }    }    int ans=0;    for (int i=1;i<=n;i++){        if (isable[i]==0)   ans+=i;    }    cout<<ans<<endl;    return 0;}



第24题

这里写图片描述
题目来源ProjectEuler

这个题是求0123456789这九个数在字典序下的第1,000,000个全排列
利用c++的next_permutation()函数循环999,999次即可。并且这一函数可以作用于char数组。

int main(){    char num[]={'0','1','2','3','4','5','6','7','8','9','\0'};    for (int i=1;i<1000000;i++){        next_permutation(num,num+10);    }    cout<<num<<endl;    return 0;}



第25题

这里写图片描述
题目来源ProjectEuler

这个题是求第一个达到1000位十进制数的斐波那契项的下标。
1000位也就是10999数量级的。
利用long double可以记录104932的值,虽然有效数字较为有限,但足够应付这个题了。其他类型的范围可参考该博客——桑海的专栏
求斐波那契数列的每一项,直到结果大于10999

int main(){    long double f1=1,f2=1,f=1;    int index=2;    long double maxx=1;    for (int i=1;i<=999;i++)    maxx*=10;    for (;f<maxx;){        index++;        f=f1+f2;        f1=f2;f2=f;    }    cout<<index<<endl;    return 0;}