Project Euler 16-20题

本文介绍了Project Euler的第16到20题的解题思路。第16题通过高精度计算求解2^1000的十进制各位数字之和;第17题手算1-1000英文表示的字母总数,得出21124的结果;第18题是动态规划的经典问题,通过一维动态规划数组求解最大路径和;第19题通过模拟计算1901年至2000年有多少个星期天是月份的第一天;第20题类似第16题,求解100!的十进制各位数字之和。
第16题

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

这个题是求 21000 在十进制表示下各位数字的和。
我没想到很好的算法,只想到一个 O(n2) 的高精度处理,直接求出结果,再一位一位加起来。

int main(){
    int num[1000],len=0;
    num[0]=1;
    for (int i=1;i<=1000;i++){
        int tmp=0;
        for (int j=0;j<=len;j++){
            num[j]<<=1;
            if(tmp==1){
                tmp=0;
                num[j]++;
            }
            if (num[j]>9){
                num[j]-=10;tmp=1;
            }
        }
        if (tmp)    num[++len]=1;
    }
    int ans=0;
    for (int i=0;i<=len;i++)    ans+=num[i];
    cout<<ans<<endl;
    return 0;
}



第17题

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

题目求的是1-1000这1000个数用英文表示出来总共有多少个字母。
这个题是我手算的,并没有写代码。我觉得这时候写代码反而是一个吃力不讨好的过程。感觉这题可以给差评了。
容易发现:
1,2,3,……,98,99这99个数是每一百个数就要出现一次的,所以一共出现了10次,答案是 85410=8540
one hundred,two hundred,……,nine hundred这些表示百位的数各出现了100次,答案是 99100=9900
而用于连接百位和其余两位的and单词从100开始,每一百个数出现99次,答案是 3999=2673
剩下的是one thousand这个单词,包含11个字母。
全部加起来就是答案21124。


第18题

这里写图片描述
题目来源ProjectEuler
这个题求顶点到最层的各路径中最大路径和是多少,是动态规划的经典入门题。
考虑每个数到底层的最大路径。
dp[i][j]=num[i][j]+max(dp[i+1][j],dp[i+1][j+1]),[i][j] 表示第i行的第j个数。
尽管这个题二维数组并不会浪费太多空间,但依然可以压缩成一维的dp数组。

int dp[16],num[16][16];

int main(){
    int n=15;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=i;j++){
            num[i][j]=read();
        }
    }
    for (int i=1;i<=n;i++)  dp[i]=num[n][i];
    for (int i=n-1;i>=1;i--){
        for (int j=1;j<=i;j++){
            dp[j]=max(dp[j]+num[i][j],dp[j+1]+num[i][j]);
        }
    }
    cout<<dp[1]<<endl;
    return 0;   
}



第19题

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

这个题求的是1901-1-1至2000-12-31的时间中,有多少个星期天恰好是某个月的第一天。我们将周日当做每个星期的第0天。
day0 dayx 的关系就是 dayx=(day0+x)mod7
其他月份都是定的,只有2月份有平闰年之分,又考虑到这一段时间内所有被4整除的年份都是闰年。模拟一遍就好。

int main(){
    int day=(1+356)%7,ans=0;
    for (int i=1901;i<=2000;i++){
        for(int j=1;j<=12;j++){
            if (day==0) ans++;
            if (j==2){
                if (i%4==0) day=(day+29)%7;
            }
            else{
                if (j==1||j==3||j==5||j==7||j==8||j==10||j==12)
                    day=(day+31)%7; 
                else    day=(day+30)%7;         
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}



第20题

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

这个题是求 100! 的十进制表示下各位数字的和。跟16题很像,依然是只会高精度处理的做法。

int num[600],len;

int main(){
    num[1]=1;len=1;
    int n=read();
    for (int i=2;i<=n;i++){
        int tmp=0;
        for (int j=1;j<=len;j++){
            num[j]*=i;
            num[j]+=tmp;
            tmp=num[j]/10;
            num[j]%=10;
        }
        while(tmp){
            num[++len]=tmp%10;
            tmp/=10;
        }
    }
    int ans=0;
    for (int i=len;i>=1;i--){
        ans+=num[i];
    }
    cout<<ans<<endl;
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值