• abc 137 Count 1‘s 【经典思维】


    给定一串1、0数字,可以选择任意区间翻转,0会变成1,1会变成0。问区间的取值种类有多少。

    思维:

    这个题也是匹配问题,因为 0 1 是相消的, 怎么体现相消呢,一个置1,一个置-1呗。再继续思考,对于每个区间如果数 > 0 意味着1多,翻过来总体的值就变小,< 0 意味着0多,反过来总体的值就变大。找区间的最大最小值。

    再数学化一点:

    假设 a 是一个原串的 1 的数量,b 是选择的区间的 0 的数量,c 是选择的区间的 1 的数量,则翻转后串的价值是 a+b-c
    a 的数量是确定的,变的是 b-c 的数量,所以我们只需要知道 b-c 的值可能有多少种即可。所以考虑将字符 1 的位置看做数值 1,将字符 0 的位置看做数值-1这样使得区间数字和就是 b-c。

    现在问题变成给定一个数组,问区间和存在多少种不同的值
    由于数值只有 1 和-1,所以我们可以求最大区间子段和与最小区间
    子段和的差值即可

    码风一:能加就加原则,不能加就赋值

    1. for (int i = 0; i < n; i ++ ) {
    2. if(sum < 0) sum = a[i];
    3. else sum += a[i];
    4. mx = max(mx, sum);
    5. }

    码风二:tourist的思维,R(答案上界,一定是由某一个pref减去他前面的最小值),L(答案下界),    mx(维护的是当前i之前的所有的最小值),mi。 注意,这套“模板”mx和mi的更新是在r和l之后的。

    1. #include
    2. typedef long long ll;
    3. using namespace std;
    4. int main(){
    5. //std::ios::sync_with_stdio(false);
    6. //std::cin.tie(nullptr);
    7. int n;
    8. cin >> n;
    9. std::vector<int> a(n);
    10. for (int i = 0; i < n; i ++ ) {
    11. cin >> a[i];
    12. a[i] = (a[i] == 1 ? 1 : -1);
    13. }
    14. vector<int> pref(n + 1, 0);
    15. for (int i = 0; i < n; i ++ ) {
    16. pref[i + 1] = pref[i] + a[i];
    17. }
    18. int L = 0;
    19. int R = 0;
    20. int mi = 0;
    21. int mx = 0;
    22. for (int i = 1; i <= n; i ++ )
    23. {
    24. R = max(R, pref[i] - mi);
    25. L = min(L, pref[i] - mx);
    26. mx = max(mx, pref[i]);
    27. mi = min(mi, pref[i]);
    28. }
    29. cout << R - L + 1 << '\n';
    30. return 0;
    31. }

    再数学化一点:

    假设 a 是一个原串的 1 的数量,b 是选择的区间的 0 的数量,c 是选择的区间的 1 的数量,则翻转后串的价值是 a+b-c
    a 的数量是确定的,变的是 b-c 的数量,所以我们只需要知道 b-c 的值可能有多少种即可。所以考虑将字符 1 的位置看做数值 1,将字符 0 的位置看做数值-1这样使得区间数字和就是 b-c。

    现在问题变成给定一个数组,问区间和存在多少种不同的值
    由于数值只有 1 和-1,所以我们可以求最大区间子段和与最小区间
    子段和的差值即可

    再数学化一点:

    假设 a 是一个原串的 1 的数量,b 是选择的区间的 0 的数量,c 是选择的区间的 1 的数量,则翻转后串的价值是 a+b-c
    a 的数量是确定的,变的是 b-c 的数量,所以我们只需要知道 b-c 的值可能有多少种即可。所以考虑将字符 1 的位置看做数值 1,将字符 0 的位置看做数值-1这样使得区间数字和就是 b-c。

    现在问题变成给定一个数组,问区间和存在多少种不同的值
    由于数值只有 1 和-1,所以我们可以求最大区间子段和与最小区间
    子段和的差值即可

  • 相关阅读:
    【Linux】 grep命令使用
    6-4 在一个数组中实现两个堆栈 分数 15
    求所有质因子(Java)
    详解Python中的json库
    2023第十四届蓝桥杯国赛 C/C++ 大学 B 组 (赛后记录)
    rknn_server启动方法
    【网络安全】文件包含漏洞--使用session进行文件包含
    ChatGPT AIGC 完成超炫酷的大屏可视化
    美团二面:SpringBoot读取配置优先级顺序是什么?
    黑客帝国:随机字母生成器
  • 原文地址:https://blog.csdn.net/IsayIwant/article/details/126592348