o1 爆切 F 题

Correct Approach:

  1. Modeling the Problem as a Markov Chain:

    • States: Each state represents the current word being spoken (from 1 to ( n )).
    • Transitions:
      • From state 1:
        • Move to state 2 with probability ( \frac{a_1}{a_1 + b_1} ).
        • Stay at state 1 with probability ( \frac{b_1}{a_1 + b_1} ).
      • From state ( i ) (( 2 \leq i \leq n-1 )):
        • Move to state ( i+1 ) with probability ( \frac{a_i^2}{a_i^2 + 2a_i b_i + b_i^2} ).
        • Stay at state ( i ) with probability ( \frac{2a_i b_i}{a_i^2 + 2a_i b_i + b_i^2} ).
        • Move back to state ( i-1 ) with probability ( \frac{b_i^2}{a_i^2 + 2a_i b_i + b_i^2} ).
      • From state ( n ):
        • Absorbing state (stop speaking).
  2. Setting Up the System of Linear Equations:

    • Let ( E[i] ) denote the expected number of words spoken starting from word ( i ).
    • For ( i < n ): [ E[i] = 1 + P(i \rightarrow i-1) \cdot E[i-1] + P(i \rightarrow i) \cdot E[i] + P(i \rightarrow i+1) \cdot E[i+1] ]
    • Rearranging: [ (1 - P(i \rightarrow i)) \cdot E[i] - P(i \rightarrow i-1) \cdot E[i-1] - P(i \rightarrow i+1) \cdot E[i+1] = 1 ]
    • For ( i = n ): [ E[n] = 1 ]
    • This forms a tridiagonal system which can be efficiently solved using the Thomas Algorithm.
  3. Implementing the Thomas Algorithm:

    • Forward Sweep:
      • Modify the coefficients to eliminate the lower diagonal.
    • Backward Substitution:
      • Solve for the expected values starting from the last equation.
  4. Handling Modular Arithmetic:

    • Since the problem requires the answer modulo ( 10^9 + 7 ), we must perform all calculations under this modulus.
    • Fractions are handled using modular inverses.
  5. Edge Cases:

    • If ( n = 1 ), the expected number of words spoken is simply 1.

Final Implementation:

Below is the corrected C++ implementation based on the above reasoning. The key correction involves properly handling the last word by adjusting the condition in the loop that sets up the tridiagonal system.

#include <bits/stdc++.h>
using namespace std;


typedef long long ll;


const int MOD = 1000000007;


// Fast exponentiation to compute x^e mod MOD
ll powmod_func(ll x, ll e, ll mod) {
    ll res = 1;
    x %= mod;
    if(x < 0) x += mod;
    while(e > 0){
        if(e & 1){
            res = res * x % mod;
        }
        x = x * x % mod;
        e >>=1;
    }
    return res;
}


int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    if(n ==1){
        cout << "1";
        return 0;
    }
    vector<ll> a(n-1), b(n-1);
    for(int i=0;i<n-1;i++) cin >> a[i];
    for(int i=0;i<n-1;i++) cin >> b[i];
    // Initialize A, B, C, D
    // A: lower diagonal, size n-1
    // B: main diagonal, size n-1
    // C: upper diagonal, size n-1
    // D: constants, size n-1
    vector<ll> A(n-1,0), B_coeff(n-1,0), C(n-1,0), D(n-1,0);
    for(int i=0;i<n-1;i++){
        if(i ==0){
            // i=0 corresponds to word1
            ll a1 = a[i];
            ll b1 = b[i];
            ll denom = (a1 + b1) % MOD;
            ll inv_denom = powmod_func(denom, MOD-2, MOD);
            // P_forward = a1 / (a1 + b1)
            ll P_forward = a1 * inv_denom % MOD;
            // P_stay = b1 / (a1 + b1)
            ll P_stay = b1 * inv_denom % MOD;
            // Set up equation: (1 - P_stay) * E0 - P_forward * E1 =1
            B_coeff[i] = (1 - P_stay + MOD) % MOD; // 1 - P_stay
            C[i] = (MOD - P_forward) % MOD; // -P_forward
            D[i] =1;
        }
        else{
            ll ai = a[i];
            ll bi = b[i];
            ll denom = (ai * ai % MOD + 2 * ai % MOD * bi % MOD + bi * bi % MOD) % MOD;
            ll inv_denom = powmod_func(denom, MOD-2, MOD);
            // P_forward = a_i^2 / denom
            ll P_forward = (ai * ai % MOD) * inv_denom % MOD;
            // P_stay = 2 * a_i * b_i / denom
            ll P_stay = (2 * ai % MOD * bi % MOD) * inv_denom % MOD;
            // P_backward = b_i^2 / denom
            ll P_backward = (bi * bi % MOD) * inv_denom % MOD;
            if(i < n-2){
                // Normal variable
                A[i] = (MOD - P_backward) % MOD; // -P_backward
                B_coeff[i] = (1 - P_stay + MOD) % MOD; // 1 - P_stay
                C[i] = (MOD - P_forward) % MOD; // -P_forward
                D[i] =1;
            }
            else{
                // Last variable (i = n-2 corresponds to word n-1)
                A[i] = (MOD - P_backward) % MOD; // -P_backward
                B_coeff[i] = (1 - P_stay + MOD) % MOD; // 1 - P_stay
                C[i] =0; // No upper diagonal for the last equation
                // D[i] =1 + P_forward * E_n, where E_n =1
                D[i] = (1 + P_forward) % MOD;
            }
        }
    }
    // Forward sweep
    vector<ll> cprime(n-1,0), dprime(n-1,0);
    // i=0
    ll B0 = B_coeff[0];
    ll C0 = C[0];
    ll D0 = D[0];
    ll invB0 = powmod_func(B0, MOD-2, MOD);
    cprime[0] = C0 * invB0 % MOD;
    dprime[0] = D0 * invB0 % MOD;
    // i=1 to n-2
    for(int i=1;i<n-1;i++){
        ll Ai = A[i];
        ll Bi = B_coeff[i];
        ll Ci = C[i];
        ll Di = D[i];
        // temp = B[i] - A[i] * cprime[i-1}
        ll temp = (Bi + MOD - (Ai * cprime[i-1] % MOD)) % MOD;
        if(temp ==0){
            // No solution, but per problem constraints, it's always solvable
            // To avoid division by zero, set E=0 (though it shouldn't happen)
            cprime[i] =0;
            dprime[i] =0;
            continue;
        }
        ll inv_temp = powmod_func(temp, MOD-2, MOD);
        cprime[i] = (Ci * inv_temp) % MOD;
        dprime[i] = ((Di + MOD - (Ai * dprime[i-1] % MOD)) % MOD * inv_temp) % MOD;
    }
    // Back substitution
    vector<ll> E(n-1,0);
    E[n-2] = dprime[n-2];
    for(int i=n-3;i>=0;i--){
        E[i] = (dprime[i] + MOD - (cprime[i] * E[i+1] % MOD)) % MOD;
    }
    // The answer is E[0]
    cout << E[0];
}

Explanation of Corrections:

  1. Condition Adjustment:

    • Original Issue: The original code incorrectly treated the last variable (corresponding to the second last word) as a normal variable.
    • Correction: The condition if(i < n-2) correctly identifies whether the current word is a normal word or the last word. This ensures that the last word's transition probabilities are handled appropriately.
  2. Handling the Last Variable:

    • For the last variable (word ( n-1 )), there is no ( E[n] ) because ( E[n] = 1 ) is known.
    • The equation for the last variable is adjusted to account for this by setting ( C[i] = 0 ) and adjusting ( D[i] ) accordingly.
  3. Modular Inverse:

    • All divisions are handled using modular inverses to ensure correctness under modulo ( 10^9 + 7 ).
  4. Ensuring Non-Zero Denominators:

    • The code includes a check to avoid division by zero, though according to problem constraints, the system should always be solvable.

Validation with Sample Input:

Let's validate the corrected code with the provided sample:

Input:

3
1 1
1 1

Expected Output:

9

Explanation:

  • Word 1:
    • ( P(1 \rightarrow 2) = \frac{1}{2} )
    • ( P(1 \rightarrow 1) = \frac{1}{2} )
  • Word 2:
    • ( P(2 \rightarrow 3) = \frac{1}{4} )
    • ( P(2 \rightarrow 2) = \frac{1}{2} )
    • ( P(2 \rightarrow 1) = \frac{1}{4} )
  • Word 3:
    • Absorbing state, ( E[3] = 1 )

Solving the system: [ \begin{cases} 0.5 E_1 - 0.5 E_2 = 1 \ -0.25 E_1 + 0.5 E_2 = 1.25 \end{cases} ] Solving these equations yields ( E_1 = 9 ) and ( E_2 = 7 ), which matches the expected output.

Conclusion:

The corrected code now accurately sets up and solves the tridiagonal system representing the Markov chain of Zaoly's speech. By properly handling the last variable and ensuring the correct conditions in the loop, the code now produces the expected results, including for the provided sample input.

全部评论
leetcode早都被橄榄了
点赞 回复 分享
发布于 2024-09-16 23:47 广东

相关推荐

辅助位:定时器项目都被用烂了,感觉
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务