Project Euler 11-15题

话说刚刚才注意到Project Euler的提交时间记录的是UTC

第11题

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

这一题与第8题类似,不过这个求的是八个方向上的最值。虽然这个也可以有类似移动窗口的做法,但是考虑到长度只有四,O(nlendirection) 的复杂度也不高,而移动窗口的代码复杂度会高很多。所以选择了裸暴力的做法。
(期间因为cal函数没有return,debug十余分钟-_-!!!)

long long num[21][21];

long long cal(int x,int y,int dx,int dy){
    long long ans=1;
    if (x+3*dx>=1&&x+3*dx<=20&&y+3*dy>=1&&y+3*dy<=20)
        for (int cnt=1;cnt<=4;cnt++,x+=dx,y+=dy){
            ans*=num[x][y];
        }
    return ans;
}

int main(){
    for (int i=1;i<=20;i++){
        for (int j=1;j<=20;j++){
            num[i][j]=read();
        }
    }
    long long ans=1,tmp=0;
    for (int i=1;i<=20;i++){
        for (int j=1;j<=20;j++){
            tmp=max(max(max(cal(i,j,-1,-1),cal(i,j,-1,0)),max(cal(i,j,0,-1),cal(i,j,-1,1))),max(max(cal(i,j,1,-1),cal(i,j,0,1)),max(cal(i,j,1,0),cal(i,j,1,1))));
            //上一行就是将以[i][j]为起点的八个方向的最值保存到tmp中
            ans=max(tmp,ans);
        }
    }
    cout<<ans<<endl;
    return 0;
}



第12题

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

这个题是求第一个有超过500个因子的triangle number。
triangle number定义为ni=1i
若将一个数x表示为x=ni=1pyii ,其中p为质数
那么x的因子数量为ni=1(yi+1)
我在Project Euler 1-5题#3中解释并证明过O(n) 时间内求一个数n的pi 的做法。通过少量改动,我们还可以求出yi
虽然利用Project Euler 6-10题#7中的性质可以优化到近似O(nlnn) ,但这个整体需要一个线性时空的预处理,我觉得实际意义并不很大。

int check(int x){
    int ans=1,num=x;
    for (int i=2,tmp;i*i<=x;i++){
        tmp=1;
        while (num%i==0){
            num/=i;
            tmp++;//tmp即yi
        }
        ans*=tmp;
    }
    if (num!=1) ans*=2;
    return ans;
}

int main(){
    for (int i=1;;i++){
        int ans=i*(i+1)/2;
        if (check(ans)>500) {
            cout<<i<<' '<<ans<<endl;
            return 0;
        }
    }
}



第13题

这里写图片描述
题目来源ProjectEuler
(由于题目数据过大,我只截取了部分内容)

这个题给出了100个50位数,求这100个数和的前10位。
由于C/C++ 标准库里面没有高精度类,而unsigned long long类型也只能保存最多20位数。
而即使是long double类型也没有50位的精度。那用C/C++语言这个题有两个做法(Python、Java那些自带高精度类的就直接算吧)。
一、手写高精度类,在大多数比赛中,由于数据的随机性以及罚时,大多会采用这一方法
二、至计算前十几位的结果,取最后结果的前10位输出。尽管可能碰到前若干位求和后的结果是9999999999……,后面某位的进位一路爆过去的情况,不过这个方法正确的概率依然是蛮高的。对于这个题已知数据的情况,可以试一试。我选择了前14位求和,输出结果的前十位。反正这么做对了2333(逃

int main(){
    char s[55];
    long long ans=0,tmp;
    for (int i=1;i<=100;i++){
        cin>>s;
        tmp=0;
        for (int j=0;j<=13;j++){
            tmp*=10;
            tmp+=s[j]-'0';
        }
        ans+=tmp;
    }
    int cnt=14;s[14]=0;
    while(ans){
        s[--cnt]=ans%10+'0';
        ans/=10;
    }
    s[cnt+10]=0;
    cout<<s+cnt<<endl;
    return 0;
}



第14题

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

这个题来源于一个很经典的问题,名字很多,应该还是叫3n+1问题的人多吧。
具体可参考维基百科
题目求的是小于1,000,000的所有数里面,将其计算到1,步骤最多的那个数。
我采用了一个半记忆化的dfs。对于所有10,000,000以内的数所需要的步数进行储存,10,000,000及以上的数的结果不储存。

int num[10000000];

int cal(long long x){
    if(x<=9999999){
        if (num[x]) return num[x];
        if (x&1)    return num[x]=1+cal(x*3+1);
        else        return num[x]=1+cal(x/2);
    }
    else{
        if (x&1)    return 1+cal(x*3+1);
        else        return 1+cal(x/2);
    }
}

int main(){
    num[1]=1;int ans=1,len=0;
    for (int i=1;i<1000000;i++){
        if(cal(i)>len)  len=num[i],ans=i;
    }
    cout<<ans<<endl;
    return 0;
}



第15题

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

这个题问的是在一个20*20的网格中,从左上角走到右下角有几种走法,每次只能往右或者往下。
一共要走40步,区别就在于哪几步往右,哪几步往下。结果就是C2040
考虑到Cmn=Cm1n1+Cmn1,m,n1
我们可以采用dp的方式。

long long dp[50][50];

int main(){
    dp[0][0]=1;
    for (int i=1;i<=40;i++){
        dp[i][0]=1;
        for(int j=1;j<=i;j++){
            dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
        }
    }
    cout<<dp[40][20];
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章