阅读视图

发现新文章,点击刷新页面。

Taro 支付宝小程序可观测最佳实践

为什么要做可观测?—— 解决“不可见”带来的业务风险

在 Taro 开发的支付宝小程序中,可观测性(Observability)的本质是通过数据化、实时化的监控手段,让小程序的运行状态、用户行为及系统交互“可见、可分析、可追溯”。其必要性源于小程序在实际运行中面临的三大核心挑战:

1、“黑盒化”运行环境:问题难以感知,故障发现滞后

小程序部署在支付宝客户端及云端环境中,开发者无法直接接触用户设备的真实运行状态。当出现以下问题时,若无可观测能力,往往只能依赖用户反馈或事后投诉。

典型案例:某电商小程序上线后,用户投诉“提交订单按钮点击无效”,但开发团队通过日志仅能看到“按钮渲染成功”,因缺乏用户操作路径和接口调用的关联数据,耗时 3 天才定位到是“异步数据未加载完成时按钮未禁用”的逻辑缺陷。若提前部署可观测能力,可通过用户行为流+接口状态实时发现该问题。

2、业务依赖复杂:跨端、跨服务的故障定位成本高

Taro 小程序通常依赖多方服务:前端通过 Taro 框架调用支付宝小程序 API(如支付、登录)、与后端服务交互(如订单查询、用户数据同步),甚至涉及第三方服务(如地图 SDK、营销活动平台)。任何一个环节异常都可能导致整体功能失效,但问题根源可能隐藏在任意一层,若无统一的观测数据(如接口调用链、用户操作路径、错误上下文),排查效率极低,可能导致用户流失或业务损失。

3、用户体验敏感:微小问题可能引发大规模负面反馈

支付宝小程序的用户对体验的容忍度极低——页面加载慢 1 秒可能导致 5% 的用户流失,支付流程卡顿可能直接引发投诉。但用户通常不会详细描述问题(如“首屏渲染慢是因为图片未压缩”),而是给出模糊反馈(“用不了”“太卡了”)。若无可观测能力,开发者只能通过“猜测+灰度测试”被动优化,无法精准识别影响用户体验的关键节点。

这些问题的解决依赖于对用户行为、性能指标的实时监控,而非事后统计。

把观测云作为 Taro 支付宝小程序可观测最佳实践的核心工具--落地路径与关键动作

  • 将观测云定位为小程序的“统一可观测平台”,以统一标签(如 service、env、version)贯穿指标、日志、链路、用户访问四类数据,形成端到端的观测视图。
  • 在 Taro 多端(含支付宝小程序)场景中,前端接入 RUM(用户访问监测),后端与基础设施接入 Logging/Tracing/Metrics,实现跨端、跨服务的统一观测与关联。
  • 通过“Dashboard + Explorer”构建业务与技术双视角的可观测体系,既看得到用户体验,也定位得到根。

前端 RUM 接入(Taro 支付宝小程序)

本最佳实践实验版本为 Taro v4.1.7

查看编译环境
➜  ~ taro --version 
? Taro v4.1.7
4.1.7
➜  ~ 

1、观测云后台->用户访问监测->新建应用,选择应用类型为小程序,输入应用名称、应用ID,系统会自动根据配置信息生成引入 SDK 的代码,可选择 NPM 接入或 CDN 文件接入(这里我们选择 CDN 文件方式接入)。

  • 应用名称:用于识别当前用户访问监测的应用名称。
  • 应用 ID :应用在当前工作空间唯一标识,对应字段:app_id 。

2、根据链接下载 CDN 文件,打开项目代码,在小程序项目中的 app.ts 入口文件引入观测云后台生成的配置代码。

注意项目中引入代码的位置,必须要在 App() 初始化之前,否则会出现数据无法正常采集上报,或者只能上报一小部分数据的情况。

3、本地运行项目或者打包发布测试后,通过观察接口调用发现 /v1/write/rum 接口成功调用,说明数据成功上报,可在对应应用的查看器查看上报数据。

4、js 会自动生成一个 trace_id,如果在 allowedTracingOrigins 配置了正则(本最佳实践中配置的是 *,意味着所有接口都会带 ),会在对应的请求头中加入一些参数,ddtrace 的是这几个参数。

实现效果

1、小程序部署在支付宝客户端及云端环境中,开发者直接接触用户设备的真实运行状态
进入「用户访问监测」页面—> 选择创建的对应微信小程序—> 分析看板,可以查看小程序运行中的部分重点信息。

进入「用户访问监测」页面—> 选择创建的对应微信小程序—> 查看器,可以查看小程序应用中用户访问的动作,请求资源以及项目中的报错信息等。

2、多方服务全链路打通

3、后端服务透明化,可以观测到更详细的代码级方法,开发可以快速定位

4、用户体验可视化,全局可观测

观测云为 Taro 支付宝小程序创建一份“数字神经系统”

在 Taro 开发的小程序中,可观测性不是“可选能力”,而是保障业务健康增长的必备基础设施。它通过将“不可见的运行状态”转化为“可见的数据洞察”,帮助开发者:

  • 从被动救火到主动预防(快速发现问题,降低故障损失);
  • 从经验驱动到数据驱动(精准优化体验,提升转化效率);
  • 从局部优化到全局可控(支撑规模化增长,保障业务稳定性);
  • 从单点协作到团队协同(提升研发效率,加速产品迭代)。

每日一题-找出所有稳定的二进制数组 I🟡

给你 3 个正整数 zero ,one 和 limit 。

一个 二进制数组 arr 如果满足以下条件,那么我们称它是 稳定的

  • 0 在 arr 中出现次数 恰好 为 zero 。
  • 1 在 arr 中出现次数 恰好 为 one 。
  • arr 中每个长度超过 limit 的 子数组同时 包含 0 和 1 。

请你返回 稳定 二进制数组的 数目。

由于答案可能很大,将它对 109 + 7 取余 后返回。

 

示例 1:

输入:zero = 1, one = 1, limit = 2

输出:2

解释:

两个稳定的二进制数组为 [1,0] 和 [0,1] ,两个数组都有一个 0 和一个 1 ,且没有子数组长度大于 2 。

示例 2:

输入:zero = 1, one = 2, limit = 1

输出:1

解释:

唯一稳定的二进制数组是 [1,0,1] 。

二进制数组 [1,1,0] 和 [0,1,1] 都有长度为 2 且元素全都相同的子数组,所以它们不稳定。

示例 3:

输入:zero = 3, one = 3, limit = 2

输出:14

解释:

所有稳定的二进制数组包括 [0,0,1,0,1,1] ,[0,0,1,1,0,1] ,[0,1,0,0,1,1] ,[0,1,0,1,0,1] ,[0,1,0,1,1,0] ,[0,1,1,0,0,1] ,[0,1,1,0,1,0] ,[1,0,0,1,0,1] ,[1,0,0,1,1,0] ,[1,0,1,0,0,1] ,[1,0,1,0,1,0] ,[1,0,1,1,0,0] ,[1,1,0,0,1,0] 和 [1,1,0,1,0,0] 。

 

提示:

  • 1 <= zero, one, limit <= 200

找出所有稳定的二进制数组 I

方法一:动态规划

题目要求二进制数组 $\textit{arr}$ 中每个长度超过 $\textit{limit}$ 的子数组同时包含 $0$ 和 $1$,这个条件等价于二进制数组 $\textit{arr}$ 中每个长度等于 $\textit{limit} + 1$ 的子数组都同时包含 $0$ 和 $1$(读者可以思考一下证明过程)。

按照题目要求,我们需要将 $\textit{zero}$ 个 $0$ 和 $\textit{one}$ 个 $1$ 依次填入二进制数组 $\textit{arr}$,使用 $\textit{dp}_0[i][j]$ 表示已经填入 $i$ 个 $0$ 和 $\textit{j}$ 个 $1$,并且最后填入的数字为 $0$ 的可行方案数目,$\textit{dp}_1[i][j]$ 表示已经填入 $i$ 个 $0$ 和 $\textit{j}$ 个 $1$,并且最后填入的数字为 $1$ 的可行方案数目。对于 $\textit{dp}_0[i][j]$,我们分析一下它的转换方程:

  • 当 $j = 0$ 且 $i \in [0, \min(\textit{zero}, \textit{limit})]$ 时:我们可以不断地填入 $0$,所以 $\textit{dp}_0[i][j] = 1$。

  • 当 $i = 0$,或者 $j = 0$ 且 $i \notin [0, \min(\textit{zero}, \textit{limit})]$ 时:我们没法构造可行的方案,所以 $\textit{dp}_0[i][j] = 0$。

  • 当 $i > 0$ 且 $j > 0$ 时:$\textit{dp}_0[i][j]$ 可以分别由 $\textit{dp}_0[i - 1][j]$ 和 $\textit{dp}_1[i - 1][j]$ 转移而来,分别考虑两种情况:

    • 对于 $\textit{dp}_1[i - 1][j]$:显然可以通过在 $\textit{dp}_1[i - 1][j]$ 对应的所有填入方案后再填入一个 $0$ 得到对应的可行方案。

    • 对于 $\textit{dp}_0[i - 1][j]$:当 $i \le \textit{limit}$ 时,显然可以通过在 $\textit{dp}_1[i - 1][j]$ 对应的所有填入方案后再填入一个 $0$ 得到对应的可行方案;当 $i \gt \textit{limit}$ 时,我们需要去除一些不可行的方案数。因为 $\textit{dp}_0[i - 1][j]$ 对应的所有填入方案都是可行的,而只有一种情况会在额外填入一个 $0$ 时,变成不可行,即先前已经连续填入 $\textit{limit}$ 个 $0$,对应的方案数为 $\textit{dp}_1[i - \textit{limit} - 1][j]$。

根据以上分析,我们有 $\textit{dp}_0[i][j]$ 的转移方程:

$$
\textit{dp}_0[i][j] = \begin{cases}
1, & i \in [0, \min(\textit{zero}, \textit{limit})], j = 0 \
\textit{dp}_1[i - 1][j] + \textit{dp}_0[i - 1][j] - \textit{dp}_1[i - \textit{limit} - 1][j], & i > limit, j > 0 \
\textit{dp}_1[i - 1][j] + \textit{dp}_0[i - 1][j], & i \in [0, limit], j > 0 \
0, & otherwise
\end{cases}
$$

同理,我们也可以获得 $\textit{dp}_1[i][j]$ 的转移方程:

$$
\textit{dp}_1[i][j] = \begin{cases}
1, & i = 0, j \in [0, \min(\textit{one}, \textit{limit})] \
\textit{dp}_0[i][j - 1] + \textit{dp}_1[i][j - 1] - \textit{dp}_0[i][j - \textit{limit} - 1], & i > 0, j > limit \
\textit{dp}_0[i][j - 1] + \textit{dp}_1[i][j - 1], & i > 0, j \in [0, limit] \
0, & otherwise
\end{cases}
$$

最后,稳定二进制数组的数目等于 $\textit{dp}_0[\textit{zero}][\textit{one}] + \textit{dp}_1[\textit{zero}][\textit{one}]$。

###C++

class Solution {
public:
    int numberOfStableArrays(int zero, int one, int limit) {
        vector<vector<vector<long long>>> dp(zero + 1, vector<vector<long long>>(one + 1, vector<long long>(2)));
        long long mod = 1e9 + 7;
        for (int i = 0; i <= min(zero, limit); i++) {
            dp[i][0][0] = 1;
        }
        for (int j = 0; j <= min(one, limit); j++) {
            dp[0][j][1] = 1;
        }
        for (int i = 1; i <= zero; i++) {
            for (int j = 1; j <= one; j++) {
                if (i > limit) {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
                } else {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                }
                dp[i][j][0] = (dp[i][j][0] % mod + mod) % mod;
                if (j > limit) {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
                } else {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                }
                dp[i][j][1] = (dp[i][j][1] % mod + mod) % mod;
            }
        }
        return (dp[zero][one][0] + dp[zero][one][1]) % mod;
    }
};

###Java

class Solution {
    public int numberOfStableArrays(int zero, int one, int limit) {
        final long MOD = 1000000007;
        long[][][] dp = new long[zero + 1][one + 1][2];
        for (int i = 0; i <= Math.min(zero, limit); i++) {
            dp[i][0][0] = 1;
        }
        for (int j = 0; j <= Math.min(one, limit); j++) {
            dp[0][j][1] = 1;
        }
        for (int i = 1; i <= zero; i++) {
            for (int j = 1; j <= one; j++) {
                if (i > limit) {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
                } else {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                }
                dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
                if (j > limit) {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
                } else {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                }
                dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
            }
        }
        return (int) ((dp[zero][one][0] + dp[zero][one][1]) % MOD);
    }
}

###C#

public class Solution {
    public int NumberOfStableArrays(int zero, int one, int limit) {
        const long MOD = 1000000007;
        long[][][] dp = new long[zero + 1][][];
        for (int i = 0; i <= zero; i++) {
            dp[i] = new long[one + 1][];
            for (int j = 0; j <= one; j++) {
                dp[i][j] = new long[2];
            }
        }
        for (int i = 0; i <= Math.Min(zero, limit); i++) {
            dp[i][0][0] = 1;
        }
        for (int j = 0; j <= Math.Min(one, limit); j++) {
            dp[0][j][1] = 1;
        }
        for (int i = 1; i <= zero; i++) {
            for (int j = 1; j <= one; j++) {
                if (i > limit) {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
                } else {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                }
                dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
                if (j > limit) {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
                } else {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                }
                dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
            }
        }
        return (int) ((dp[zero][one][0] + dp[zero][one][1]) % MOD);
    }
}

###Go

func numberOfStableArrays(zero int, one int, limit int) int {
    dp := make([][][2]int, zero + 1)
    mod := int(1e9 + 7)
    for i := 0; i <= zero; i++ {
        dp[i] = make([][2]int, one + 1)
    }
    for i := 0; i <= min(zero, limit); i++ {
        dp[i][0][0] = 1
    }
    for j := 0; j <= min(one, limit); j++ {
        dp[0][j][1] = 1
    }
    for i := 1; i <= zero; i++ {
        for j := 1; j <= one; j++ {
            if i > limit {
                dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1]
            } else {
                dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1]
            }
            dp[i][j][0] = (dp[i][j][0] % mod + mod) % mod
            if j > limit {
                dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0]
            } else {
                dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0]
            }
            dp[i][j][1] = (dp[i][j][1] % mod + mod) % mod
        }
    }
    return (dp[zero][one][0] + dp[zero][one][1]) % mod
}

###Python

class Solution:
    def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
        dp = [[[0, 0] for _ in range(one + 1)] for _ in range(zero + 1)]
        mod = int(1e9 + 7)
        for i in range(min(zero, limit) + 1):
            dp[i][0][0] = 1
        for j in range(min(one, limit) + 1):
            dp[0][j][1] = 1
        for i in range(1, zero + 1):
            for j in range(1, one + 1):
                if i > limit:
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1]
                else:
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1]
                dp[i][j][0] = (dp[i][j][0] % mod + mod) % mod
                if j > limit:
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0]
                else:
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0]
                dp[i][j][1] = (dp[i][j][1] % mod + mod) % mod
        return (dp[zero][one][0] + dp[zero][one][1]) % mod

###C

#define MOD 1000000007

int numberOfStableArrays(int zero, int one, int limit) {
    long long dp[zero + 1][one + 1][2];
    memset(dp, 0, sizeof(dp));
    for (int i = 0; i <= (zero < limit ? zero : limit); ++i) {
        dp[i][0][0] = 1;
    }
    for (int j = 0; j <= (one < limit ? one : limit); ++j) {
        dp[0][j][1] = 1;
    }
    for (int i = 1; i <= zero; ++i) {
        for (int j = 1; j <= one; ++j) {
            if (i > limit) {
                dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
            } else {
                dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
            }
            dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
            if (j > limit) {
                dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
            } else {
                dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
            }
            dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
        }
    }
    int result = (dp[zero][one][0] + dp[zero][one][1]) % MOD;
    return result;
}

###JavaScript

const MOD = 1000000007;

var numberOfStableArrays = function(zero, one, limit) {
    const dp = Array.from({ length: zero + 1 }, () =>
        Array.from({ length: one + 1 }, () => [0, 0])
    );

    for (let i = 0; i <= Math.min(zero, limit); i++) {
        dp[i][0][0] = 1;
    }
    for (let j = 0; j <= Math.min(one, limit); j++) {
        dp[0][j][1] = 1;
    }

    for (let i = 1; i <= zero; i++) {
        for (let j = 1; j <= one; j++) {
            if (i > limit) {
                dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
            } else {
                dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
            }
            dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
            if (j > limit) {
                dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
            } else {
                dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
            }
            dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
        }
    }
    return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
};

###TypeScript

const MOD = 1000000007;

function numberOfStableArrays(zero: number, one: number, limit: number): number {
    const dp: number[][][] = Array.from({ length: zero + 1 }, () =>
        Array.from({ length: one + 1 }, () => [0, 0])
    );

    for (let i = 0; i <= Math.min(zero, limit); i++) {
        dp[i][0][0] = 1;
    }
    for (let j = 0; j <= Math.min(one, limit); j++) {
        dp[0][j][1] = 1;
    }

    for (let i = 1; i <= zero; i++) {
        for (let j = 1; j <= one; j++) {
            if (i > limit) {
                dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit - 1][j][1];
            } else {
                dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
            }
            dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
            if (j > limit) {
                dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit - 1][0];
            } else {
                dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
            }
            dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
        }
    }
    return (dp[zero][one][0] + dp[zero][one][1]) % MOD;
};

###Rust

const MOD: i32 = 1000000007;

impl Solution {
    pub fn number_of_stable_arrays(zero: i32, one: i32, limit: i32) -> i32 {
        let mut dp = vec![vec![vec![0; 2]; one as usize + 1]; zero as usize + 1];

        for i in 0..=zero.min(limit) as usize {
            dp[i][0][0] = 1;
        }
        for j in 0..=one.min(limit) as usize {
            dp[0][j][1] = 1;
        }

        for i in 1..=zero as usize {
            for j in 1..=one as usize {
                if i > limit as usize {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1] - dp[i - limit as usize - 1][j][1];
                } else {
                    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1];
                }
                dp[i][j][0] = (dp[i][j][0] % MOD + MOD) % MOD;
                if j > limit as usize {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0] - dp[i][j - limit as usize - 1][0];
                } else {
                    dp[i][j][1] = dp[i][j - 1][1] + dp[i][j - 1][0];
                }
                dp[i][j][1] = (dp[i][j][1] % MOD + MOD) % MOD;
            }
        }
        (dp[zero as usize][one as usize][0] + dp[zero as usize][one as usize][1]) % MOD
    }
}

复杂度分析

  • 时间复杂度:$O(\textit{zero} \times \textit{one})$,其中 $\textit{zero}$ 和 $\textit{one}$ 分别为 $0$ 和 $1$ 的出现次数。

  • 空间复杂度:$O(\textit{zero} \times \textit{one})$。

逐步优化 DP 状态

前记:读了读别人的题解,感觉 newhar 老师的思路更清晰易懂一点,推荐大家看 newhar 的题解,这里就记一下自己的解法。

解法:DP

以下题解中把 limit 简记为 $l$。

转化题目条件

首先,题目要求序列中恰好出现 zero 个 $0$ 以及 one 个 $1$,显然序列的长度必须为 zero + one。记序列的长度为 $n$。

只要一个子数组包含 $0$ 和 $1$,那么所有完全包含它的子数组也会包含 $0$ 和 $1$。因此,题目中“arr 中每个长度超过 $l$ 的子数组都同时包含 $0$ 和 $1$”这一条件可以重写为:

arr 中每个长度恰为 $(l + 1)$ 的子数组都同时包含 $0$ 和 $1$。

设计 DP 状态

考虑任一下标 $i$,假设 $i$ 左边最近的 $0$ 到 $i$ 的距离是 $p_i$($p_i = 0$ 说明 arr[i] == 0),$i$ 左边最近的 $1$ 到 $i$ 的距离是 $q_i$($q_i = 0$ 说明 arr[i] == 1)。不妨假设下标 $i$ 是某个长度为 $(l + 1)$ 的子数组的右端点,因为这个子数组里既有 $0$ 又有 $1$,那么我们同时有 $p_i \le l$ 以及 $q_i \le l$。

由此可以设计出朴素的 DP 状态。设 $f(i, j, p, q)$ 表示考虑序列的前 $i$ 个元素中有 $j$ 个 $1$,且 $i$ 到最近的 $0$ 距离为 $p$,到最近的 $1$ 距离为 $q$ 的方案数。但这样状态总数为 $\mathcal{O}(n^2l^2)$,无论是 C 题还是 D 题都无法通过。

优化 DP 状态

注意到元素要么是 $0$ 要么是 $1$,也就是说对于任意的 $i$,$p = 0$ 和 $q = 0$ 恰有一个成立。因此可以将 DP 状态压缩为 $f(i, j, t = 0/1, d)$ 表示考虑序列的前 $i$ 个元素中有 $j$ 个 $1$,且第 $i$ 个元素填的是 $t$,$i$ 到最近的另一种元素(即 $1 - t$)距离为 $d$ 的方案数。这样状态总数为 $\mathcal{O}(n^2l)$。

转移方程分为两部分。

f(i, j, 0, d) += f(i - 1, j, 0, d - 1)
f(i, j, 1, d) += f(i - 1, j - 1, 1, d - 1)

这一部分的含义是,让第 $i$ 个元素和第 $(i - 1)$ 个元素相同,那么到另一种元素的距离自然增加 $1$。

f(i, j, 0, 1) += f(i - 1, j, 1, *)
f(i, j, 1, 1) += f(i - 1, j - 1, 0, *)

这一部分的含义是,让第 $i$ 个元素和第 $(i - 1)$ 个元素不同,那么到另一种元素(也就是上一个元素)的距离就是 $1$。这里的星号通过维护前缀和即可 $\mathcal{O}(1)$ 计算。

初值就是枚举第一个元素填 $0$ 还是 $1$。对于第一个元素来说,另一种元素已经 $1$ 个位置没出现了,所以 $d = 1$,即 $f(1, 0, 0, 1) = f(1, 1, 1, 1) = 1$。

整体复杂度 $\mathcal{O}(n^2l)$,可以通过 C 题。

继续优化 DP 状态

我们发现,DP 主要的运算复杂度来自转移方程的第一部分。第一部分的转移方程看起来很简单,好像只是把上一个位置所有 $(d - 1)$ 的 DP 值都照搬过来而已。由于 $d \le l$ 的限制,只是丢弃了 $f(i - 1, j, *, l)$ 的 DP 值。而 DP 方程的第二部分没有丢弃任何 DP 值,通过前缀和直接把所有情况照单全收。

这里其实在暗示我们:只要上个位置距离另一种元素的距离不到 $l$,那么当前位置无论填什么都是安全的。只有上个位置距离另一种元素的距离恰为 $l$ 时,当前位置必须填与上个位置不同的元素。也就是说:

(当前位置填元素 t 的方案数) = (上个位置的所有方案数) - (元素 1 - t 最近一次在 i - limit - 1 出现,从 i - limit 到 i 全部都是元素 t 的方案数)

设 $f(i, j, t = 0/1)$ 表示考虑序列的前 $i$ 个元素中有 $j$ 个 $1$,且第 $i$ 个元素填的是 $t$ 的方案数。“元素 $(1 - t)$ 最近一次在 $(i - l - 1)$ 出现,从 $(i - l)$ 到 $i$ 全部都是元素 $t$ 的方案数”怎么算呢?当然就是 $f(i - l - 1, j', 1 - t)$。这里 $j'$ 要看如果 $t = 0$ 那么 $j' = j$,否则如果 $t = 1$ 那么由于从 $(i - l)$ 到 $i$ 全部都是 $1$,则 $j' = j - l - 1$。

由此得到转移方程.

f(i, j, 0) = f(i - 1, j, 0) + f(i - 1, j, 1) - f(i - l - 1, j, 1)
f(i, j, 1) = f(i - 1, j - 1, 0) + f(i - 1, j - 1, 1) - f(i - l - 1, j - l - 1, 0)

整体复杂度 $\mathcal{O}(n^2)$,可以通过 D 题。

但是,实现过程中有一个初值的细节问题。当 $i = l + 1$ 时,我们要求 “元素 $(1 - t)$ 最近一次在下标 $0$ 出现的方案数”。空序列一定是合法的,所以有 $f(0, 0, 0) = f(0, 0, 1) = 1$。然而当 $i = 1$ 的时候,这样的初值设置会导致 $f(i - 1, j, 0) + f(i - 1, j, 1)$ 这部分的转移方程出现重复计算,所以我们直接继续设置初值 $f(1, 0, 0) = f(1, 1, 1) = 1$。

参考代码(c++)

###c++

class Solution {
public:
    int numberOfStableArrays(int zero, int one, int limit) {
        const int MOD = 1e9 + 7;
        int n = zero + one;

        long long g[n + 1][one + 1][2];
        memset(g, 0, sizeof(g));
        g[0][0][0] = g[0][0][1] = g[1][0][0] = g[1][1][1] = 1;

        auto update = [&](long long &x, long long y) {
            x = (x + y) % MOD;
        };

        for (int i = 2; i <= n; i++) {
            for (int j = 0; j <= one; j++) {
                update(g[i][j][0], g[i - 1][j][1] + g[i - 1][j][0]);
                if (i > limit) update(g[i][j][0], MOD - g[i - 1 - limit][j][1]);

                if (j > 0) update(g[i][j][1], g[i - 1][j - 1][0] + g[i - 1][j - 1][1]);
                if (i > limit && j > limit) update(g[i][j][1], MOD - g[i - 1 - limit][j - 1 - limit][0]);
            }
        }

        return (g[n][one][0] + g[n][one][1]) % MOD;
    }
};

iPhone 17e 上手体验:「苹替」的平替,今年少有的性价比?

如果说,去年在官网看到 iPhone 16e,我有一种非常「下头」的感觉,那么今年的 iPhone 17e,却让我「上头」了好几天。

和 iPhone 标准版对比,iPhone 17e 还是那台刀法精准的「入门款」,但整台手机给人的气质,又完全不同。

爱范儿已经提前拿到了 iPhone 17e,我们给它找了三个对手互相 PK,一起来看看,这台「真香机」究竟值不值得买。

VS iPhone 16e:升级都踩在点子上

不得不说,苹果对 iPhone 17e 的几个改动,都是相当精准和到点的。

从外观上看,iPhone 17e 和 iPhone 16e 几乎毫无差别,正面依旧「刘海」,背面还是「单摄」——不对,iPhone 17e 这次还多了一个全新的「淡粉」配色。

▲ 左:iPhone 16e;右:iPhone 17e,如果不是新配色,几乎完全没差别

iPhone 16e 只有黑白两种基础配色,仿佛作为一款入门机型,不值得花心思选个好看的配色。

今年的 iPhone 17e 的淡粉色不仅颜值高,还是 iPhone 17 系列中唯一一款粉配色,属于是标准版和 Pro 都没有的待遇。

新颜色是外在升级,而 iPhone 17e 的一个内在升级,则是 MagSafe 磁吸这个呼声极高的功能,终于补上了。

不管是充电宝、补光灯、卡包还是散热背夹,iPhone 17e 不用再靠手机壳,能够无缝解锁整个磁吸生态。

更重要的是,支持 MagSafe 后,iPhone 17e 无线充电功率最高可达 15W,和 iPhone 17 Pro 保持一致,是 iPhone 16e Qi 无线充电功率的两倍。

和配色类似,即使你不使用 MagSafe,它依然是一个「加分项」,提升整机性价比,同时让人感觉它更像是「iPhone 17 家族」的一员。

虽然正面屏幕还是 iPhone 14 同款,苹果这次给 iPhone 17e 换上了 iPhone 17 同款的第二代超瓷晶面板,根据官网的表述,抗刮划能力是 iPhone 16e 的 3 倍,可以省下一笔贴膜的钱。

另一个「看不见」的变化,则是 iPhone 17e 搭载的全新 A19 处理器。和前代一样,是标准版 6 核 CPU + 4 核 GPU 的「减配版」,对比 iPhone 17 少了一个 GPU 核心。

▲ iPhone 17 家族

去年的 iPhone 17 已经证明,制程更先进的 A19 对比上一代 A18 提升非常明显。我们用 iPhone 17e 和 iPhone 16e 跑了跑分和游戏,看看实际提升有多高。

从跑分来看,即使 iPhone 17e 和 iPhone 16e 一样同为 5 核 GPU,前者的 A19 芯片图形性能还是要强大不少。

《明日方舟:终末地》20 分钟,iPhone 17e 的平均帧率 43.1,iPhone 16e 的平均帧率 36.1,从帧率曲线看,iPhone 17e 也要更稳定,而 iPhone 16e 会在 30 帧和 60 帧之间反复横跳。总体来说游玩的体验相近,不过 iPhone 16e 的机身反而会没那么烫手。

影像从来不是 iPhone 16e 的强项,iPhone 17e 在硬件规格上也没明显提升,用它来记录生活可以,要求它出片就稍微有点强人所难了。

从各个方面来看,iPhone 17e 和 iPhone 16e 之间的差别不大,不过升级都算踩在了点子上——实用的 MagSafe,以及 A19 的强大性能。

iPhone 17e 在起售价保持 4499 元不变的同时,起始存储从 128GB 升级到了 256GB,对于还在用几年前小存储 iPhone 的用户来说,确实很值得升级。

即使是 iPhone 16e,全新的 256GB 版本,恐怕价格上也不会比 17e 低太多。

VS iPhone 17:有差距,但更有差价

那么,这么超值的 iPhone 17e,对比同样「挤爆牙膏」的 iPhone 17,又该如何抉择?

价格上,两者就已经有显著差异。去年,iPhone 16e 发布时,iPhone 16 国补渠道价已经来到了 4699 元,和 3999 的 iPhone 16e 没差太多,因此我们都更推荐方方面面更胜一筹的 iPhone 16。

目前,iPhone 17 的渠道价格在 5499 元左右,根据去年 iPhone 16e 的情况,可以合理推断 iPhone 17e 的国补价格大概在 3999 元,差价 1500 元。

这 1500 元,首先能买到一个 120Hz 的高刷屏幕,还是窄边框设计配灵动岛,这些配置让 iPhone 17 都更像一台「新 iPhone」,一块更好的屏幕,对使用体验的提升是立竿见影的。

至于影像能力,少一个超广角的焦段不必提,iPhone 17e 的主摄传感器尺寸还比 iPhone 17 要更小,因而解析力略逊一筹,暗光场景差距会明显一点。

▲ iPhone 17 天更蓝草更绿

比起硬件素质,更致命的是拍照功能上的缺失,特别是可调色摄影风格,以及前置自拍可以横图竖拍的 Center Stage 这两个口碑很好的功能,都在 iPhone 17e 上缺席了。

▲ iPhone 17 上的 Center Stage 自拍功能

考虑到这个世界上除了摄影师还有很多随手拍的玩家,我们之前也写过,在 Project Indigo 的加持下,即便同样单摄的 iPhone Air 也能成为街拍神器——所以影像方面就见仁见智了。

做工则是很多人会忽略,但上手就会发现的差异,iPhone 17e 后者边框和背板之间没有做圆润的过渡,并且磨砂玻璃后盖的工艺也要比 iPhone 17 要粗粝不少。

性能方面,两者的差异主要集中在 GPU 核心数量,这也实打实体现在了跑分上。

但从实际的游戏表现来看,iPhone 17 30 分钟《终末地》平均帧率 43.4,和 iPhone 17 的 43.1 可以说相差无几,后者会相对稳一点。

个人认为,这些体验、配置上的差距,确实对得起两台手机之间 1500 元的差价,苹果推出 iPhone 17e,某种程度更加「衬托」iPhone 17 的「真香」。

如果你对高刷、影像、性能都不感冒,只想要一台「好用」的手机,那无疑 iPhone 17e 是值得推荐的。

如果说,去年的 iPhone 16e 我总觉得买给父母有点「亏」,其他的选择更有性价比;iPhone 17 多出来的配置,对长辈而言也许不太敏感;在我心目中,iPhone 17e 就是父母和学生用机的第一选择。

最后,如果是双卡用户,购买 iPhone 17e 时要注意:iPhone 17e 只支持一个实体卡槽,如果想要双卡双待,至少其中一张卡必须是 eSIM。

VS 国产中端新机:「苹替」的平替?

不管是官网的配置,还是上面的对比评测, 其实都可以看出,iPhone 17e 和 iPhone 16e,进步其实并没有那么明显,无非就是 MagSafe、A19、新配色、256GB 起步。

去年,爱范儿认为 iPhone 16e 是一台「酱香型手机」,它还不错,只是不值得马上买,需要等渠道降价将它的性价比释放出来。

一年过去,情况已经大有不同。从去年年底开始,一场元器件成本的风暴席卷了整个消费电子行业,内存价格暴涨,所有品牌、所有价位的厂商,今年推出的新机大概率都免不了价格上涨、配置缩水的命运。

而原本 3500-4000 这个价位,也就是华为 nova、OPPO Reno、vivo S 这类「走量」的中端系列,将会显著受到这一波涨价的冲击,价格被迫提到之前的旗舰档,内存 8GB、存储 128GB 的手机可能还会重出江湖。

▲ vivo S50

在这种万马齐喑的行业寒冬时刻,苹果推出的入门款产品,不仅没涨价,还给加塞了个 MagSafe,以及 256GB 存储起步。

之所以去年的 iPhone 16e 被诟病「不够性价比」,也是和同价位国产手机比较略逊一筹;而现在对手涨价和缩水难免,逆潮流的 iPhone 17e 不仅有质价比,还「被迫」有了性价比。

有意思的是,这些国产中端机这几年喜欢用「苹替」一词进行包装和营销,而 iPhone 17e,某种意义上就是这些「苹替」的「平替」。

于是乎,苹果和国产品牌的处境,好像微妙地发生了置换。

过去,「性价比」从来不是苹果的标签,因此 Android 才有了走「便宜大碗」的生存空间,苹果这个价位没有的高刷大屏、超广长焦,全部都安排上。在 4000 元左右的中端档位,苹果用 iPhone SE、iPhone 16e 挑战,效果一直以来不算很好。

但现在,苹果凭借强大的供应链管理能力,价位和配置能顶着压力继续慷慨,而国产 Android 手机的定价,却只能随着成本水涨船高。

某种意义上说,面对比以往都显得更有诚意的 iPhone 17e,面临压力的国产 Android 旗舰反而成了「挑战者」。

当然,目前我们还不能知道国产中端机比以前贵多少,如果你还是觉得国补价的 iPhone 17e 买不下手,那我建议你再等等。

差不多两个月后,今年第一波国产入门机型也会发布,到时候不仅可以比较一下两者的配置、价格,顺便也有机会看到 iPhone 17e 的价格进一步走低。

这也许是今年少有的,还值得一等的消费电子产品了。

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

爱范儿 | 原文链接 · 查看评论 · 新浪微博


八亿时空:全资子公司拟1.56亿元出售南通詹鼎11.5892%股权

36氪获悉,八亿时空公告,公司全资子公司八亿投资管理公司拟向南通詹鼎实际控制人陈朝琦转让其所持有的南通詹鼎11.5892%的股权,转让价格为人民币15,645.40万元。本次交易不构成关联交易,不构成重大资产重组。交易尚需提交公司股东会审议,且后续尚需完成款项支付、工商变更等手续。

宁德时代:拟注册发行不超过400亿元债券

36氪获悉,宁德时代公告,公司于2026年3月9日召开的第四届董事会第十四次会议审议通过了《关于拟注册发行债券的议案》,为满足生产经营和业务发展需求,优化债务结构,降低融资成本,公司拟注册发行不超过400亿元(含400亿元)的债券。该议案尚需经公司2025年年度股东会审议通过后方可实施。

网易LobsterAI接入企业微信、QQ、飞书、钉钉

36氪获悉,3月8日,网易LobsterAI(有道龙虾)0.2.2版本正式接入企业微信及QQ机器人,叠加此前钉钉、飞书的移动端支持,已实现主流IM全覆盖。本次更新后,用户通过手机端的企微或QQ 即可直接向Agent下达指令并获取结果——无论是复杂数据分析、PPT 生成还是实时理财监控,用户均可随时随地在手机端给网易LobsterAI(有道龙虾)“派活”,远程驱动Agent完成复杂任务。

*ST松发:申请撤销公司股票退市风险警示

36氪获悉,*ST松发公告,公司已按照《上海证券交易所股票上市规则》的相关规定自查,公司股票触及被实施退市风险警示的情形已消除,满足申请撤销退市风险警示的条件。公司已向上海证券交易所提交撤销申请,上海证券交易所将在收到申请后15个交易日内决定是否撤销退市风险警示。在上海证券交易所审核期间,公司股票不停牌,仍正常交易。最终申请撤销情况以上海证券交易所审核意见为准。

宁德时代:2025年净利润722亿元,同比增长42.28%

36氪获悉,宁德时代发布2025年业绩报告。报告显示,2025年营业收入4237.02亿元,同比增长17.04%;归属于上市公司股东的净利润722亿元,同比增长42.28%;经营活动产生的现金流量净额1,332亿元,同比增长37.35%。在动力电池领域,全球市占率突破历史新高,储能电池出货量连续5年位居全球第一。

同花顺:2025年净利润32.05亿元,同比增长75.79%

36氪获悉,同花顺公告,2025年营业收入60.29亿元,同比增长44.00%。净利润32.05亿元,同比增长75.79%。公司董事会审议通过的利润分配预案为:以5.38亿为基数,向全体股东每10股派发现金红利51元(含税),送红股0股(含税),以资本公积金向全体股东每10股转增4股。

揭秘闪充建站成本,比亚迪也玩「百亿补贴」!

当时发布的时候,我们充电桩的数量,以及很多软硬件当时都还没有。现在回过头来看,这些都是教训。当然,也是财富了。

比亚迪闪充发布会后,爱范儿和董车会参加了一场媒体沟通会。会上,比亚迪集团品牌及公关处总经理李云飞用这样一段话,复盘了去年初发布第一代兆瓦闪充技术的经历。

有了上一次的经验,比亚迪这次换了一种打法。

在喊出「9 分钟充饱」这一口号之前,他们已经派出了 2000 人的团队,在全国各地建好了 4239 座闪充站。到今年年底,这个计划的目标是两万座。

用最省钱的方式,花掉上百亿

确认了建站目标,大家最关心的自然是资金投入。

一套包含储能模块的闪充桩造价并不低,李云飞在采访中给出了大致的数字,每套装置的成本在大几十万元的级别。按照今年两万座的建站规划,这笔账目算下来需要实打实地掏出上百亿元。

「几百亿对比亚迪目前的体量来说没有任何问题,这笔钱必须要花。」李云飞说。

虽说是几百亿的大生意,但比亚迪具体的推行方式却非常「轻量化」,和特斯拉、小鹏、理想的那种自建站的方式并不一样。

实际上,比亚迪采用了一套最省钱的方法来铺开充电网络。他们大量推行「站中站」模式,也就是在现有的第三方充电站里直接安装一根或多根闪充设备。而在官方公布的这 2 万座闪充站里,有 18000 座都是属于站中站模式。

李云飞详细描述了这套设备的现场施工流程:

我们现在去外部建这个闪充站的时候,都不需要去挖地基了,(整个流程)就跟装空调一样。发过去以后的话,直接装一个地台,金属框架上面有螺丝,往地下一打,直接(把充电桩)放上去就行,电一接就完事了。

这种极度简化的施工过程,得益于设备自带的储能系统。因为不需要向地方电网申请额外的容量配额,原有的线路就足以支撑储能电池在夜间或闲时进行蓄电。

对于第三方场站的运营方来说,这种合作模式也有着很强的吸引力。

李云飞透露了前期实地调研的数据,目前市面上很多公共充电站的平均利用率只有 5% 左右。大量车位在闲置,充电枪的翻台率极低。

我们过去以后,合作方是非常欢迎的。就相当于他开了一个饭馆,我们说我们带朋友带客人去,我们还自带锅碗瓢盆,且可以给他带来巨大的客流。

李云飞用通俗的语言解释了这种互利关系。自带储能设备的闪充站入驻后,能吸引自家的闪充车主,也会因为对全行业开放而带来其他品牌的用户。比亚迪认为,这会大幅提升原有场站的整体利用率。

为了配合快速铺开的建站节奏,比亚迪在发布会上推出了一个「圆梦建站」的计划。只要凑够 4 个车主提出建站需求,官方承诺会在一周内完成实地考察并建好新站。

李云飞坦言这是向行业学习的营销经验。从发布会当晚到第二天下午,后台已经收到了大量用户的建站需求。这套机制能够精准定位真实的补能盲区,把钱花在刀刃上。

除了基建层面的讨论,也有人好奇,第二代刀片电池全面推向市场后,现有的第一代产品会不会面临停产淘汰的局面。

李云飞给出了明确的答复。

没有清退一说,我们一代跟二代是并存的。我们也是想给客户更多的选择。有些客户对这个闪充无感,那还是考虑现有的第一代电池和现有的产品解决方案。

他补充提到,对于日常习惯在家里慢充的用户,哪怕充电时间被压缩到五分钟或者十分钟,他们也不会有太强烈的感知。因此,比亚迪希望能够保持产品线的多样性,让不同需求的用户都能找到合适的价格区间。

顺着家庭充电的场景,李云飞还提出了一个观点:随着公共快充站的普及和充电时间的缩短,家庭充电桩在未来可能会失去存在的意义。

「如果说充电跟加油一样快的话,还有必要去装家桩吗?」李云飞算了一笔账。

很多地方装家充桩受很多条件限制。你要装家充桩,首先物业得给你拉线、增容,这是要成本的。另外为了兼容交流慢充,车上还必须配一个 AC 交流充电机装置,也将近一两千块钱。这一进一出都是成本,虽然看似是客户掏钱,但实际上是整个社会的资源浪费。

在比亚迪看来,与其让车主和物业去死磕这些安装门槛,不如用一套覆盖极广、效率极高的公共闪充网络,来集中解决诸多电动化难题。

把选择权交还市场

在发布会上,为了制造足够的视觉冲击力,比亚迪重点展示了续航超过 1000 公里的纯电旗舰车型。但在比亚迪实际的销量基盘里,插电混动车型占据着极大的比重。

当被问及这些车型的充电表现时,李云飞在交流会现场做了一个补充说明。

无论是混动车还是纯电动车,无论它纯电的续航里程是多少,是 400 公里还是 1000 公里,无论是多少度电,它都能统一的做成 5 分钟充好,9 分钟充饱,零下 30 度只加 3 分钟。

这其实并不是比亚迪一家的独角戏,仔细观察当下的汽车市场,发力混动车型的充电速度已经成为头部车企的共识。以小鹏汽车发布的鲲鹏超级电动体系为例,这套主打增程混动的动力方案同样配备了 5C 超充电池,把电量从 10% 充到 80% 的时间压缩到了 12 分钟。

▲ 上周发布的小鹏 G6 超级增程版

补能效率的大幅提升,自然会让外界拿这套兆瓦闪充网络去和行业里现有的换电模式做对比。有人好奇这是否会引发一场激烈的路线之争。

李云飞给出了他的看法。

我觉得闪充和换电都挺好。比亚迪推出各种技术和品牌,目的就是给客户提供更多选择。对于行业来说,就需要百花齐放,殊途同归。看起来闪充和换电是不一样的路线,但共同路线都是促进油转电。

至于这些最顶尖的电池技术是否会对外供应,李云飞给出了肯定的答复。目前比亚迪的电池业务已经在给国内外十几个汽车品牌供货。第二代刀片电池未来同样会对外开放,但短期内需要优先满足内部需求,并留出足够的产能爬坡时间。

回到整车产品线的规划上,闭门交流会还透露了一个重要的策略转变。

过去几年,比亚迪在高端品牌上有着很强的技术捆绑执念。李云飞在现场进行了反思。

「我们原来也有一种执念,技术一定要区别。仰望就是易四方,其他品牌想要易四方,不行,不给。」李云飞觉得这种做法存在局限性,因为随着市场竞争加剧,消费者对价格变得极其敏感。

如今为了顺应市场,他们开始进行大刀阔斧的配置解绑。

以刚刚发布的新车为例,腾势 Z9GT 推出了单电机版本,起售价从当初的 33.48 万元来到了 26.98 万元,仰望 U7 搭载的云辇-Z 智能悬架系统也不再是全系强制标配。

「有些客户对易三方无感,你非得给他加这么多硬件,硬件冗余就是成本,成本的话就是价格。所以我们还是遵从市场,遵从客户的考虑。」李云飞表示,把是否需要极致操控的选择权交还给消费者,通过降低非必要硬件的冗余,可以提供更多元的价格区间,让产品覆盖更广的人群。

过去几年,国产高端新能源车热衷于通过疯狂堆砌旗舰级软硬件来拉高品牌定位。但在价格战的持续洗礼下,普通用户变得越来越精打细算。一些用户开始意识到,自己并不需要为那些日常通勤几乎用不到的东西买单。比如,云辇-Z 和易三方。

比亚迪的目标人群同样覆盖海外。

「我们在海外闪充站的建设落地可能会晚于国内,大概在 2026 年年底。」李云飞说。

他认为,现阶段的国内消费者「非常幸福」。在燃油车时代,外资品牌的新车往往在海外卖了好几代才会引入中国。而在如今的智能化和电动化时代,情况完全反过来了。

中国品牌基本上在国内先销售一两年,逐渐把国内的车型再引入到海外。最好的产品,最好的价格,最好的服务都在国内。

带轮子的都关注,欢迎交流。 邮箱:tanjiewen@ifanr.com

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

爱范儿 | 原文链接 · 查看评论 · 新浪微博


❌