• 1065 最小正子段和 二分答案 + 判定


    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1065

    我的思路比较笨,我是直接二分那个答案mid

    然后进行一次O(nlogn)的判定,如果能找到一个区间的和比mid小的,(当然这个区间的和也是要大于0),那就return true

    进行判断如下:

    处理出前缀和dp[i],对于每一个i

    目标是:在前i - 1个中,查看是否有这样的一个x,使得,dp[i] - x    <=   mid,&& dp[i] - x >= 1

    二分找x,把前i - 1个东西压去set中,然后二分找x >= dp[i] - mid的那个x,判定即可。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 50000 + 20;
    LL dp[maxn];
    int n;
    set<LL>ss;
    bool check(LL val) {
        if (dp[1] <= val && dp[1] >= 1) return true;
        ss.clear();
        ss.insert(0);
        ss.insert(dp[1]);
        LL mx = max(0LL, dp[1]);
        for (int i = 2; i <= n; ++i) {
            LL x = dp[i] - val;
            if (mx < x) {
                mx = max(mx, dp[i]);
                ss.insert(dp[i]);
                continue;
            }
            set<LL> :: iterator it = ss.lower_bound(x);
            if (dp[i] - *it >= 1) return true;
            mx = max(mx, dp[i]);
            ss.insert(dp[i]);
        }
        return false;
    }
    void work() {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            int x;
            scanf("%d", &x);
            dp[i] = dp[i - 1] + x;
        }
    //    for (int i = 1; i <= n; ++i) {
    //        cout << dp[i] << " ";
    //    }
    //    cout << endl;
        LL be = 1, en = 1e18L;
    //    cout << check(1) << endl;
        while (be <= en) {
            LL mid = (be + en) >> 1;
            if (check(mid)) {
                en = mid - 1;
            } else be = mid + 1;
        }
    //    cout << be << endl;
        printf("%lld
    ", be);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code

    这题的正解是:

    预处理前缀和,然后按从小到大排序,相同时再按位置从小到大排序

    比如前缀和是,3、1、2

    排序后是1(2)、2(3)、3(1),括号的是位置

    那么3不能作为贡献,因为他前面没有比他位置小的数字。

    一开始以为这样找也是O(n^2),但是发现好像只需要比较相邻的两位就可以,

    给个数据

    4

    -1、-1、-1、8

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 50000 + 20;
    struct node {
        LL val;
        int pos;
        bool operator < (const struct node & rhs) const {
            if (val != rhs.val) return val < rhs.val;
            else return pos < rhs.pos;
        }
    }a[maxn];
    void work() {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            int x;
            scanf("%d", &x);
            a[i].val = a[i - 1].val + x;
            a[i].pos = i;
        }
        sort(a + 1, a + 1 + n);
        LL ans = 1e18L;
        if (a[1].val >= 1) ans = a[1].val;
        for (int i = 2; i <= n; ++i) {
            if (a[i].val >= 1) ans = min(a[i].val, ans);
            if (a[i].pos > a[i - 1].pos && a[i].val - a[i - 1].val >= 1) {
                ans = min(ans, a[i].val - a[i - 1].val);
            }
        }
        cout << ans << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    LeetCode 50: Pow(x, n)
    Codility 1: equilibrium
    LeetCode 49: Anagrams
    crackme160--(5)
    crackme160--(4)
    魔兽显血改键工具的脱壳和修改
    crackme160--(3)
    crackme160--(1)
    python-装饰器
    编程语言C++01-C++入门学习路线
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6352198.html
Copyright © 2020-2023  润新知