1. 程式人生 > >Codeforces-161-E(快速冪,)

Codeforces-161-E(快速冪,)

Codeforces 161E-Tetrahedron

本篇文章部分參考於

題目原址

題意

一個正四面體頂點為A,B,C,D,從D出發,每走一步,更變當前所在頂點(不能保持不變),給定一個數 n ,求能有幾種不同路徑使得第 n 步走到 D。

題解

  • 方法一(遞推)O(n)O(n)
    分兩種情況:1.第 n-2 步不在 D, 2.第 n-2 步在 D
    a[n] 是第 n 步到達 D 的不同路徑數。
    · 對於 1 情況:第 n-2 步在A,B,C當中的一點,那麼這時,在第 n-1 步能夠到達 D,但其實他可以選擇在第 n-1 到達另外兩點,然後在第 n 步到達D,所以這種情況有 2a[n-1]
    種。
    · 對於 2 情況:第 n-2 步在D點,那麼他可以通過走到A,B,C中的任意一點,再回到D點,所以這種情況有 3a[n-2] 種。
    · 故有 a[n]=2a[n-1]+3a[n-2]
  • 方法二(公式)(O(log2n)O(log_{2}{n}))
    有上述公式,就能用特徵方程解出 a[n] 表示式,對於任意的:An=pAn1+qAn2A_{n}=pA_{n-1}+qA_{n-2}有特徵方程可寫成:x2=px+qx^{2}=px+q若其有解x1x2x_{1},x_{2},則有:An=ax1n1+bx2n
    1A_{n}=ax_{1}^{n-1}+bx_{2}^{n-1}
    於是我們可以根據方法一中的表示式得出:an=34(3n1(1)n1)(n>1)a_{n}=\frac{3}{4}(3^{n-1}-(-1)^{n-1})~~(n>1)於是再運用快速冪來求3n13^{n-1}即可。還要尋找 4 的逆元,否則無法邊運算邊取模,很容易發現 mod+14\frac{mod+1}{4}4mod 中的逆元。(因為 mod = 1e9+7)
  • 方法三(動態規劃)
    O(n)O(n)
    dp[i][j] 表示第 i 步走到 j 點,則有:dp[i][j]=dp[i][j]+dp[i1][k](jk)dp[i][j]=dp[i][j]+dp[i-1][k]~~(j\ne{k})於是從遍歷i,j,k,最後取 dp[n][3] 即可
  • 方法四(概率)
    n 步的總共不同路徑有3n3^{n}條,若算出第 n 點到達 D 的概率,最後乘上3n3^{n}再取模即可。· 設Pn(A)P_{n}(A)為第 n 步到達 A 點的概率,那麼由對稱性可知:Pn(A)+Pn(B)+Pn(C)+Pn(D)=1P_{n}(A)+P_{n}(B)+P_{n}(C)+P_{n}(D)=1又知A,B,C三點完全等價,故有Pn(A)=Pn(B)=Pn(C)=1Pn(D)3P_{n}(A)=P_{n}(B)=P_{n}(C)=\frac{1-P_{n}(D)}{3}然後又可知第 n-1 步必定在A,B,C當中一點,且無論在哪一點總有13\frac{1}{3}的概率走到D,故有:Pn+1(D)=13(Pn(A)+Pn(B)+Pn(C))=1Pn(D)3P_{n+1}(D)=\frac{1}{3}(P_{n}(A)+P_{n}(B)+P_{n}(C))=\frac{1-P_{n}(D)}{3}結合P1(D)=0P_{1}(D)=0可算出Pn(D)P_{n}(D)的表示式為:3nPn(D)=34(3n1(1)n1)3^{n}P_{n}(D)=\frac{3}{4}(3^{n-1}-(-1)^{n-1})

實現1(遞推)

#include <stdio.h>
const int mod = (int)1e9 + 7;
const int maxn = (int)1e7 + 5;
long long a[maxn];
int main() {
    int n;
    scanf("%d", &n);
    int i;
    a[0] = 3;
    a[1] = 6;
    for (i = 2; i <= n-2; i++)
        a[i] = (2 * a[i - 1] + 3 * a[i - 2])%mod;
    printf("%I64d\n", a[n-2]);
}

實現1`(遞推,優化空間)

#include <stdio.h>
const int mod = (int)1e9 + 7;
const int maxn = (int)1e7 + 5;
int main() {
    int n;
    scanf("%d", &n);
    int i;
    long long a=1,b=0,c=0;
    for (i = 2; i <= n; i++){        
        c = (2 * b + 3 * a)%mod;        
        a=b;        
        b=c;
    }
    printf("%I64d\n", c);
}

實現2(公式,快速冪)

#include <stdio.h>
const int mod = (int)1e9 + 7;
const int inv4 = (mod + 1) / 4;//4的逆元
    long long qpow(long long c, int n) {//快速冪
    long long ans=1;
    while (n > 0) {
        if (n & 1)            
        ans =ans*c%mod;        
        c=c*c%mod;        
        n >>= 1;
    }
    return ans;
}
int solve(int n) {
    long long ans;
    if (n & 1)        
        ans = (3 * (qpow(3, n - 1) - 1))%mod * inv4 %mod;
    else        
    ans = (3 * (qpow(3, n - 1) + 1))%mod * inv4 %mod;
    return (int)ans;
}
int main() {
    int n;
    scanf("%d", &n);
    printf("%d\n", solve(n));
}

實現3(動態規劃)

#include <stdio.h> 
const int mod = (int)1e9 + 7; 
int d[(int)1e7+5][4];//0=A,1=B,2=C,3=D 
int main() {     
    int n;     
    scanf("%d", &n);     
    d[1][0] = d[1][1] = d[1][2] = 1;    
    for (int i = 1; i <= n; i++)        
        for (int j = 0; j < 4; j++)            
            for (int k = 0; k < 4; k++)                
                if (j != k)                    
                    d[i][j] = (d[i][j] + d[i - 1][k]) % mod;    
    printf("%d", d[n][3]);
}