Project Euler 21-25题

第21题

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

这个题定义了一个函数 d(x)=divisori ,其中 divisori x 的因子且!=x
求小于10,000的所有满足 d(d(a))==a a 的和。
首先求所有数不为本身的因子的和。如果一个数一个数去分解,复杂度将会是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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值