• Codeforces Round #600 (Div. 2)


    传送门

    A. Single Push

    直接乱搞即可。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/16 22:36:20
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
     
    int n;
    int a[N], b[N], c[N];
     
    void run(){
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i];
        for(int i = 1; i <= n; i++) {
            cin >> b[i];
            c[i] = b[i] - a[i]; 
        }
        int cnt = 0;
        for(int i = 1; i <= n; i++) {
            if(c[i] < 0) return pt("NO");
        }
        int l = 1, r = n;
        while(l <= r && c[l] == 0) ++l;
        while(l <= r && c[r] == 0) --r;
        int ok = 1;
        for(int i = l + 1; i <= r; i++) if(c[i] != c[i - 1]) ok = 0;
        if(l > r || ok) return pt("YES");
        else return pt("NO");
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T;
        while(T--) run();
    	return 0;
    }
    

    B. Silly Mistake

    贪心分组即可。
    用一个(map)记录当前组一个人是否已经来过。
    至于为什么用(map),方便清零= =

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/16 22:50:46
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e6 + 5;
     
    int n;
    int a[N];
     
    map <int, int> mp, mp2;
     
    void run(){
        for(int i = 1; i <= n; i++) cin >> a[i];
        int tot = 0, last = 0;
        vector <int> ans;
        for(int i = 1; i <= n; i++) {
            if(a[i] > 0) {
                if(mp.find(a[i]) == mp.end() && mp2.find(a[i]) == mp2.end()) {
                    mp[a[i]] = 1; 
                    ++tot;
                } else {
                    cout << -1;
                    return ;
                }
            } else {
                if(mp.find(-a[i]) != mp.end()) {
                    mp.erase(-a[i]);
                    --tot;
                    mp2[-a[i]] = 1;
                } else {
                    cout << -1;
                    return;   
                }
            }
            if(tot == 0 && sz(mp) == 0) {
                ans.push_back(i - last);
                mp2.clear();
                last = i;   
            }
        } 
        if(tot || sz(mp) != 0) {
            cout << -1;
            return ;   
        }
        cout << sz(ans) << '
    ';
        for(auto it : ans) cout << it << ' ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n) run();
    	return 0;
    }
    

    C. Sweets Eating

    顺序没关系,排序后贪心分组即可。
    公式推一推就行。
    难点是读题。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/16 23:12:15
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5;
     
    int n, m;
    int a[N];
    ll ans[N], sum[N];
     
    void run(){
        for(int i = 1; i <= n; i++) cin >> a[i];
        sort(a + 1, a + n + 1);
        for(int i = 1; i <= n; i++) {
            sum[i] = sum[i - 1] + a[i];
            if(i <= m) ans[i] = sum[i];
        }
        for(int i = m + 1; i <= n; i++) {
            ans[i] = sum[i] + ans[i - m];   
        }
        for(int i = 1; i <= n; i++) cout << ans[i] << " 
    "[i == n];
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m) run();
    	return 0;
    }
    

    D. Harmonious Graph

    题意:
    给出一个(n)个结点,(m)条边的无向图。
    然后如果一个图(l)能到达(r),那么对于所有的(m,l<m<r),都有(m)能够到达(r)
    现在问这个图中最少添加多少条边,使得这个图满足上述情况。

    思路:

    • 显然一个连通块中,只有最大值和最小值有用。
    • 那么可以认为每个连通块形成一段区间。注意到若两个区间相交或包含,那么肯定需要连一条边以满足条件。

    那么最终就相当于一个区间合并的问题,注意一下单独的点也可以形成一个区间。
    细节详见代码:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/16 23:21:00
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5;
     
    int n, m;
    vector<int> g[N];
    bool chk[N], vis[N];
    int mx, mn;
     
    void dfs(int u) {
        vis[u] = 1;
        mx = max(mx, u);
        mn = min(mn, u);
        for(auto v : g[u]) if(!vis[v]) dfs(v);   
    }
     
    struct node{
        int l, r;   
        bool operator < (const node &A) const {
            return l < A.l;   
        }
    }a[N];
     
    void run(){
        for(int i = 1; i <= m; i++) {
            int u, v; cin >> u >> v;
            g[u].push_back(v), g[v].push_back(u);
        }
        int tot = 0;
        for(int i = 1; i <= n; i++) {
            if(!vis[i]) {
                mx = 0, mn = INF;
                dfs(i);   
                a[++tot] = node{mn, mx};
            }
        }
        sort(a + 1, a + tot + 1);
        int rb = 0;
        int ans = 0;
        for(int i = 1, j; i <= tot; i = j) {
            j = i + 1;
            rb = max(rb, a[i].r);
            while(j <= tot && rb >= a[j].l) {
                rb = max(rb, a[j].r);
                ++j;
            }
            ++ans;
        }
        //dbg(tot, ans);
        ans = tot - ans;
        cout << ans << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m) run();
    	return 0;
    }
    

    E. Antenna Coverage

    题意:
    范围为([1,m])的坐标轴上有(n)个点,每个点都有其半径(r_i)
    现在可以多次执行操作:选择一个点,使其半径增加(1)
    问至少多少次操作,使得这个坐标轴上每个整点至少被一个点覆盖。

    思路:
    解法一:

    • 连边跑最短路即可满足“最小”的要求。
    • 具体连边方法为:(i ightarrow i+1),若两个点都被覆盖,则边权为(0),否则为(1),表示需要扩展(1)的半径;对于每个点,枚举其半径扩展的所有情况,连边(i ightarrow j),边权为相应花费。
    • 第二种方式连边时,为方便处理,采用左闭右开区间的形式。
    • 显然,一个点只能被左边或右边的一个点扩展后覆盖,以上两种连边方式即可表示出这种情况。
    • 还有一种连边方法:第二种没变,第一种改为(i ightarrow i-1),边权为(0),表示可以往回走。正确性脑补一下即可。

    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/17 19:10:25
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
     
    int n, m;
    bool f[N];
    int x[N], r[N];
     
    struct Edge{
        int u,v,w,next ;
    }e[N * 80];
    int head[N], tot;
    struct node{
        int d,u;
        bool operator < (const node &A)const{
            return d>A.d;
        }
    };
    void adde(int u,int v,int w){
        e[tot].v=v;e[tot].w=w;e[tot].next=head[u];head[u]=tot++;
    }
    int d[N];
    bool vis[N];
    void Dijkstra(int s){
        priority_queue <node> q;
    	memset(d, INF, sizeof(d));
        memset(vis, 0, sizeof(vis)); d[s]=0;
        q.push(node{0, s});
        while(!q.empty()){
            node cur = q.top(); q.pop();
            int u = cur.u;
            if(vis[u]) continue ;
            vis[cur.u] = 1;
            for(int i = head[u]; i != -1; i = e[i].next){
                int v = e[i].v;
                if(d[v] > d[u] + e[i].w){
                    d[v] = d[u] + e[i].w;
                    q.push(node{d[v], v});
                }
            }
        }
    }
     
    void run(){
        memset(head, -1, sizeof(head));
        for(int i = 1; i <= n; i++) {
            cin >> x[i] >> r[i];
            for(int j = max(1, x[i] - r[i]); j <= min(m, x[i] + r[i]); j++) f[j] = 1;
        }
        for(int i = 2; i <= m + 1; i++) {
            if(f[i] && f[i - 1]) adde(i - 1, i, 0);
            else adde(i - 1, i, 1); 
        }
        for(int i = 1; i <= n; i++) {
            int L = max(1, x[i] - r[i]), R = min(m, x[i] + r[i]);
            int mx = max(L - 1, m - R);   
            for(int j = 0; j <= mx; j++) {
                adde(max(1, L - j), min(m + 1, R + j + 1), j);
            }
        }
        Dijkstra(1);
        cout << d[m + 1];
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m) run();
    	return 0;
    }
    
    

     
    解法二:

    • 考虑(dp:dp[i])表示覆盖([1,i])的区间的最小操作次数。
    • 初始化(dp[i] = i)
    • 考虑一个点有两种情况,被覆盖或者没被覆盖。被覆盖的情况比较好转移,直接(dp[i]=min(dp[i],dp[i-1]))即可;没被覆盖的情况我们考虑从前面的一个区间延申过来,枚举前面区间转移即可。
    • 但这里可能会有点问题,就是刚才说的,一个点可能被后面的区间覆盖到,(dp)中没有考虑到这种情况(好像叫做有后效性?)。但仔细分析,其实没有后效性,若存在这种情况,当(i)枚举到后面的时候肯定会覆盖到我们此时说的这种情况,但此时是从(j,j<i)转移过来的,所以(i)的选择不会受到后面的影响。

    emmm感觉说了一大堆还是自己对(dp)的理解不是很透彻,感觉在口胡一通= =
    若有什么问题欢迎指出,thx~
    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/17 21:59:50
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
     
    int dp[N];
    int x[N], r[N];
    bool f[N];
    int n, m;
    void run(){
        for(int i = 1; i <= n; i++) {
            cin >> x[i] >> r[i];
            for(int j = max(1, x[i] - r[i]); j <= min(m, x[i] + r[i]); j++) f[j] = 1;
        }
        for(int i = 0; i <= m; i++) dp[i] = i;
        for(int i = 1; i <= m; i++) {
            if(f[i]) dp[i] = min(dp[i], dp[i - 1]);
            for(int j = 1; j <= n; j++) if(x[j] <= i) {
                int cost = max(0, i - x[j] - r[j]);
                dp[i] = min(dp[i], dp[max(0, x[j] - r[j] - cost - 1)] + cost);
            }
        }
        cout << dp[m]; 
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m) run();
    	return 0;
    }
    

    F. Cheap Robot

    题意:
    在一个(n)个结点,(m)条边的无向连通图中,有一个机器人,有(c)的能量。
    当走过一条边时,若边权为(w),则会消耗(w)的能量,能量不能为负数。
    (1)~(k)号点能够将能量补充至(c)点。
    现在给出多组询问,每组询问给出两点(a,b),询问从(a)(b)最少(c)为多少。(a,b)两点都为能量补给站。

    思路:

    • 注意限制条件能量不为负数,也就是说在中间走的过程中(c)不能降为负数。
    • (d[u])表示(u)到最近能量补给站的距离,那么我们在任何时候都可以认为在(u)点的能量为(c-d[u])
    • 限制条件转换为:若经过(u)(v)这一条边,那么有:(d[v]+wleq c-d[u]),变换一下即为:(d[u]+d[v]+wleq c)
    • 那么我们将每条边的边权重新置为(d[u]+d[v]+w)。询问要回答的就是(a,b)补给站之间最大边权的最小值。
    • 那么我们求出最小生成树,在上面搞搞就行了。

    我采用的是离线,然后启发式合并两个集合。但是一直有个问题想不通,更新答案的时候要加个取(min)操作,没有的话就要(wa)。讲道理,对于一个询问的(id)难道不是只会更新一次么。。之后就在一个集合里面了。
    希望各位大佬能告诉我为啥QAQ。
    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/18 9:06:44
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5, M = 4e5 + 5;
     
    struct Edge{
        int v, w, next;   
    }e[M << 1];
    ll dis[N];
    struct Dijkstra{
        struct node{
            ll d, u;
            bool operator < (const node &A) const {
                return d > A.d;
            }   
        };
        int head[N], tot;
        bool vis[N];
        void init() {
            memset(head, -1, sizeof(head)); tot = 0;   
        }
        void adde(int u, int v, int w) {
            e[tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++;   
        }
        void dij(int s) {
            priority_queue <node> q;
            memset(dis, INF, sizeof(dis));
            memset(vis, 0, sizeof(vis));
            dis[s] = 0;
            q.push(node{0, s});
            while(!q.empty()) {
                node cur = q.top(); q.pop();
                int u = cur.u, d = cur.d;
                if(vis[u]) continue;
                vis[u] = 1;
                for(int i = head[u]; i != -1; i = e[i].next) {
                    int v = e[i].v;
                    if(dis[v] > dis[u] + e[i].w) {
                        dis[v] = dis[u] + e[i].w;
                        q.push(node{dis[v], v});   
                    }
                }   
            }
        }
    }solver;
    int n, m, k, q;
     
    struct E {
        int u, v;
        ll w;    
        bool operator < (const E &A) const {
            return w < A.w;
        }
    }edge[M << 1];
     
    vector <pii> v[N], edges[N];
    ll ans[M];
     
    int f[N];
    int find(int x) {return f[x] == x ? f[x] : f[x] = find(f[x]);}
    set <int> s[N];
     
    void merge(int x, int y, ll z) {
        for(auto it : s[x]) {
            f[it] = y;
            for(auto t : v[it]) {
                if(s[y].find(t.fi) != s[y].end()) {
                    ans[t.se] = min(ans[t.se], z);//???
                }
            }
            s[y].insert(it);
        }   
    }
     
    void Union(int x, int y, ll z) {
        int fx = find(x), fy = find(y);
        if(fx != fy) {
            if(sz(s[fx]) < sz(s[fy])) {
                merge(fx, fy, z);
            } else {
                merge(fy, fx, z);
            } 
        }
    }
    void run(){
        solver.init();
        for(int i = 1; i <= m; i++) {
            int u, v, w; cin >> u >> v >> w;
            solver.adde(u, v, w);
            solver.adde(v, u, w);
            edges[u].push_back(MP(v, w));
        }
        for(int i = 1; i <= k; i++) solver.adde(0, i, 0);
        solver.dij(0);
        m = 0;
        for(int u = 1; u <= n; u++) {
            for(auto it : edges[u]) {
                int v = it.fi, w = it.se;
                edge[++m] = E{u, v, dis[u] + dis[v] + w};
            }   
        }
        for(int i = 1; i <= q; i++) {
            int a, b; cin >> a >> b;
            v[a].push_back(MP(b, i));
            v[b].push_back(MP(a, i));
        }
        memset(ans, INF, sizeof(ans));
        sort(edge + 1, edge + m + 1);
        for(int i = 1; i <= n; i++) f[i] = i, s[i].insert(i);
        for(int i = 1; i <= m; i++) {
            int u = edge[i].u, v = edge[i].v;
            ll w = edge[i].w;
            Union(u, v, w);
        }
        for(int i = 1; i <= q; i++) cout << ans[i] << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m >> k >> q) run();
    	return 0;
    }
    
  • 相关阅读:
    XMLHttpRequest简介
    BC30138: 无法在路径“C:\WINDOWS\TEMP\”中创建临时文件: 拒绝访问。
    开机explorer无法启动,无法进入桌面
    选择DataGrid中的CheckBox控件后该行背景变色
    CSS菜单制作工具
    ScriptX打印控件的使用
    JS实时预览上传图片缩略图
    readyState的五种状态详解
    xmlHttpRequest的status的值的含义
    C#调用word打印
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11879117.html
Copyright © 2020-2023  润新知