zoukankan      html  css  js  c++  java
  • Codeforces Round #707 Div2 A-D

    A - Alexey and Train

    模拟,没啥需要讲的,按照题目写就行了。

    #include <bits/stdc++.h>
    #define Mid (l + r << 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read() {
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    const int N = 309;
    int n, a[N], b[N], tim[N];
    void work() {
        n = read();
        for(int i = 1; i <= n; i++) {
            a[i] = read();
            b[i] = read();
        }
        for(int i = 1; i <= n; i++) tim[i] = read();
        int now = a[1] + tim[1];
        for(int i = 2; i <= n; i++) {
            if(now + (b[i - 1] - a[i - 1] + 1) / 2 >= b[i - 1]) {
                now = now + (b[i - 1] - a[i - 1] + 1) / 2;
            } else now = b[i - 1];
            now += a[i] - b[i - 1] + tim[i];
        }
        printf("%d
    ", now);
    }
    signed main()
    {
        int Case = read();
        while(Case--) work();
        return 0;
    }
    View Code

    B - Napoleon Cake

    题意:

    有一个n层的楼,对于每个(i∈[1,n]),有一个(a_i)表示从i往下数(a_i)个刷上了颜色,问每层楼有没有颜色。

    题解:

    当然可以用线段树,但是有(O(n))的差分做法,而且代码量少。
    因为不是在线询问,对于每个(a_i),在差分数组上打上标记就可以实现区间修改了,最后询问的时候求一下前缀和就行。

    #include <bits/stdc++.h>
    #define Mid (l + r << 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read() {
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    const int N = 2e5 + 1009;
    int n, a[N], f[N];
    void work() {
        n = read();
        for(int i = 0; i <= n; i++) f[i] = 0;
        for(int i = 1; i <= n; i++) {
            a[i] = read();
            f[(i - a[i] + 1) > 0 ? (i - a[i] + 1) : 1] += 1;
            f[i + 1] -= 1;
        }
        for(int i = 1; i <= n; i++) {
            f[i] += f[i - 1];
            if(f[i] > 0) printf("1 ");
            else printf("0 ");
        }
        printf("
    ");
    }
    signed main()
    {
        int Case = read();
        while(Case--) work();
        return 0;
    }
    View Code

    C - Going Home

    题意:

    给定一列数(f),要求找出四个不一样的(a,b,c,d)使得(f_a + f_b=f_c + f_d),如果没有输出(no)

    (f_ile 2.5 imes 10^6)

    题解:

    发现(f_a + f_b)是不超过(5 imes 10^6)的,我们可以开个桶存下所有的(f_a + f_b),只要一个桶里面的数量大于4,那么一定有解。

    证明:
    有四对数,则情况有以下两种:
    (A):((x, y),(x, z), (z, y), (任意))这样子最后一对一定可以跟前面配对。
    (B):((x, y),(x, z), (x, p), (x, q))虽然这四个不能匹配,但是发现都(f_x+f_i)都等于一个数(t),也就是说明(f_y=f_z=f_p=f_q)这样就可以取(f_y+f_z=f_p + f_q)

    于是,最多枚举(2 imes 10^7)个数,一定存在答案。
    暴力枚举就行了。

    不过我考场上的做法是直接暴力,有可能被卡,谨慎参考以下代码。

    #include <bits/stdc++.h>
    #define Mid (l + r << 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read() {
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    const int N = 5e6 + 1009;
    int n, a[N];
    struct node {
        int x, y;
    };
    vector<node> f[N];
    signed main()
    {
        n = read();
        for(int i = 1; i <= n; i++) a[i] = read();
        for(int l = 1; l <= n; l++) {
            for(int i = 1; i + l <= n; i++) {
                int p = a[i] + a[i + l];
                f[p].push_back((node){i, i + l});
                for(int k = 0; k < f[p].size(); k++) {
                    if(f[p][k].x == i || f[p][k].y == i) continue;
                    if(f[p][k].x == i + l || f[p][k].y == i + l) continue;
                    printf("YES
    ");
                    printf("%d %d %d %d
    ", f[p][k].x, f[p][k].y, i, i + l);
                    return 0;
                }
            }
        }
        printf("NO
    ");
        return 0;
    }
    View Code

    D - Two chandeliers

    题意:

    两队人同时循环报数,每次报数的人假如颜色不一样就计一次贡献,问第(k)次贡献产生的时候报到了几。

    两队个队伍内部没有重复颜色。

    题解:

    看官方Tutorial给的是CRT,但是我没有用CRT也水过去了。
    考场上没看见颜色各不同结果挂了,要注意审题啊

    我们先交换(n,m)使得(mle n),这样之后我们可以考虑假如(b)数组第(1)个和(a)数组第(i)个同时开始报数,(b)报回到(1)产生几个贡献。

    这是可以(O(n))处理出来的,方法如下。
    我们把(b)数组里面的数与下标进行映射,这样可以把(b)数组的颜色换成(0, 1, 2, ..., m - 1),然后考虑(a)数组内部的贡献。

    (a)数组的第(i)仅仅不会对从(i - a[i])开始的匹配产生贡献,这样我们就可以统计出从第(i)个位置开始匹配,不能产生贡献的位置个数,(m-cnt[i])就是产生的贡献个数。

    这样结束后,我们一步的跨度就是(m)了,但是还是会超时,因为可能(k)很大,而(m)很小。

    这时候我们考虑利用最小公倍数去优化枚举。
    两列数匹配的循环节是最小公倍数,我们只需要计算最小公倍数匹配的贡献,然后剩下的部分暴力匹配就行了。

    那么最小公倍数的匹配时间复杂度是多少呢?
    最小公倍数最坏情况下为(n imes m),每次跨越(m),最多循环(n)步就可以求出来了。

    接下来的就暴力了。

    #include <bits/stdc++.h>
    #define int long long
    #define Mid (l + r << 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read() {
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    const int N = 5e5 + 1009;
    int n, m, k, a[N], b[N], f[N * 2];
    int cnt[N], lcm;
    int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
    int cal(int k) {
        int q = 0, now = 1, p = 1, tot = 0;
        while(q < k) {
            if(q + cnt[now] >= k)break;
            q += cnt[now];
            now = (now - 1 + m) % n + 1;
            tot += m;
        }
        while(q < k) {
            q += (a[now] != b[p]);
            now = now % n + 1;
            p = p % m + 1;
            tot++;
        }
        return tot;
    }
    int cal1(int k) {
        int tt = k / m, q = 0;
        for(int i = 1, now = 1; i <= tt; i++) {
            q += cnt[now];
            now = (now - 1 + m) % n + 1;
        }
        return q;
    }
    signed main()
    {
        n = read(); m = read();
        k = read();
        if(n <= m) {
            swap(n, m);
            for(int i = 1; i <= m; i++) b[i] = read();
            for(int i = 1; i <= n; i++) a[i] = read();
        } else {
            for(int i = 1; i <= n; i++) a[i] = read();
            for(int i = 1; i <= m; i++) b[i] = read();
        }
        memset(f, -1, sizeof(f));
        for(int i = 1; i <= m; i++) 
            f[b[i]] = i - 1;
        for(int i = 1; i <= n; i++) {
            if(f[a[i]] != -1) {
                cnt[(i - f[a[i]] - 1 + n) % n + 1]++;
            }
        }
        for(int i = 1; i <= n; i++) 
            cnt[i] = m - cnt[i];
        int p = n / gcd(n, m) * m;
        int tt = cal1(p), ans = 0;
        ans += (k - 1) / tt * p;
        k = (k - 1) % tt + 1;
        ans += cal(k);
        printf("%lld
    ", ans);
        return 0;
    }
    /*
    cnt[i]表示从i开始匹配,能有多少个匹配上
    */
    View Code
  • 相关阅读:
    点击链接,取得href的值,但是不转向
    启动和停止MySQL服务
    QuickText for Notepad++
    otepad++ 配置 支持jquery、html、css、javascript、php代码提示
    windows 2008+IIS7+Mysql+PHP5.5 + FastCGI环境配置
    Jquery异步请求数据实例代码
    JS读取本地文件及目录的方法
    c#.net从ftp下载文件到本地
    怎样才能充分利用SQL索引
    jQuery EasyUI Datagrid性能优化专题
  • 原文地址:https://www.cnblogs.com/onglublog/p/14531508.html
Copyright © 2011-2022 走看看