zoukankan      html  css  js  c++  java
  • 2019 ACM-ICPC 上海网络赛 B. Light bulbs (差分)

    题目链接:Light bulbs
    比赛链接:The Preliminary Contest for ICPC Asia Shanghai 2019

    题意

    给定 (N) 个灯泡 (编号从 (0)(N - 1)),初始都是关闭的。

    给定 (M) 个操作,每个操作包含 (L)(R),对 ([L, R]) 内的所有灯泡改变状态。

    求最后有几个灯泡是亮的。

    思路

    题目挺简单的,翻转奇数次的灯泡是亮的,所以要求每个灯泡翻转的次数。

    容易想到可以用差分。

    对所有操作的两个端点排序,求差分数组 (d[])

    然后根据差分数组求前缀和,差分数组相邻两个数 (d[l])(d[r]) 所在的区间 ([l, r)) 内的每个数都加上 (d[l]),那么如果 (d[l]) 为奇数,(ans += (r - l))。时间复杂度 (O(MlogM))

    于是就有了下面的代码。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6 + 10;
    
    int pos[2010];
    
    int main() {
        int T;
        scanf("%d", &T);
        int kase = 0;
        while(T--) {
            int n, m;
            scanf("%d%d", &n, &m);
            vector<int> d(n + 10);
            memset(pos, 0, sizeof(pos));
            unordered_map<int, int> mp;
            int cnt = 0;
            for(int i = 1; i <= m; ++i) {
                int l, r;
                scanf("%d%d", &l, &r);
                ++d[l];
                --d[r + 1];
                if(mp[l] == 0) {
                    pos[cnt++] = l;
                    mp[l] = 1;
                }
                if(mp[r + 1] == 0) {
                    pos[cnt++] = r + 1;
                    mp[r + 1] = 1;
                }
            }
            sort(pos, pos + cnt);
            ll ans = 0;
            for(int i = 1; i < cnt; ++i) {
                if(d[pos[i - 1]] & 1) ans += pos[i] - pos[i - 1];
                d[pos[i]] = d[pos[i - 1]] + d[pos[i]];
            }
            if(d[pos[cnt - 1]] & 1) ans += n - pos[cnt - 1];
            printf("Case #%d: %lld
    ", ++kase, ans);
        }
        return 0;
    }
    

    然后就 TLE 了。这题时间和空间卡的很紧。

    AC 代码

    用 map 存差分数组,还自动排序了。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6 + 10;
    
    int main() {
        int T;
        scanf("%d", &T);
        int kase = 0;
        while(T--) {
            int n, m;
            scanf("%d%d", &n, &m);
            map<int, int> d;
            int cnt = 0;
            for(int i = 1; i <= m; ++i) {
                int l, r;
                scanf("%d%d", &l, &r);
                ++d[l];
                --d[r + 1];
            }
            ll ans = 0;
            auto it = d.begin();
            int p = it->first;
            int v = it->second;
            ++it;
            for(; it != d.end(); ++it) {
                if(v & 1) ans += it->first - p;
                it->second = v + it->second;
                p = it->first;
                v = it->second;
            }
            if(v & 1) ans += n - p;
            printf("Case #%d: %lld
    ", ++kase, ans);
        }
        return 0;
    }
    
  • 相关阅读:
    LeetCode 38. 外观数列
    LeetCode 33. 搜索旋转排序数组
    LeetCode 31. 下一个排列
    LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置
    LeetCode 29. 两数相除
    LeetCode 22. 括号生成
    LeetCode 1. 两数之和
    LeetCode 17. 电话号码的字母组合
    LeetCode 18. 四数之和
    LeetCode 16. 最接近的三数之和
  • 原文地址:https://www.cnblogs.com/wulitaotao/p/11524929.html
Copyright © 2011-2022 走看看