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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章