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 广东

相关推荐

牛客84809583...:举报了
点赞 评论 收藏
分享
白火同学:只是实习的话,你这份简历应该也差不多了。真要优化的话,因为面实习的话,没有开发经验,面试更重视技术栈水平。 1、重视JavaSE的基础吧,集合、泛型算是比较基础的基础,多线程、反射、JVM内存模型才是基础; 2、技术栈写到具体的点,比如Elasticsearch的使用写到某个点,限制面试官自由发挥,防止问了相关问题最后又答不上,如果真没把握建议不写,降低面试官的心理预期; 3、技术栈不要重复,比如技术栈第二条和第八条可以合并改为“熟悉Redis中间件,包括基本数据结构、缓存策略、持久化机制,了解缓存三剑客及其解决方案,并有相关项目经验。”; 4、项目指标量化,比如“达到xx秒的响应速度”(不过这个就有点偏校招社招的要求了,实习简历不写也无伤大雅)。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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