zoukankan      html  css  js  c++  java
  • 联赛前第七阶段总结

    和12差70分,模拟赛21不知道挂了多少,模拟赛24挂了80,事实证明挂一场考试没什么事,挂两场我就不行啦
    由于正在专心改T1的时候老姚催总结,所以口糊了几行上去

    总结
    和第12差70分,昨天上午挂了80分。。。
    
    这个阶段开局28名,本来可以追上来,结果因为用vector越界然后RE了,就止步于15名了。
    
    挂一场其实没啥,挂两场就不行了,还是太菜了
    
    问题就是改题效率太低,不会的一定要抓紧时间看题解搞懂
    

    晚间测试13

    阶段排名 15

    暴踩std!!!

    A Dove 打扑克

    • nmlog搞了65,然后就去看T2了,和正解好像只差一个set

    • 比正解还多了个树状数组。

    • set里维护都有那些集合大小出现过,然后枚举就好,直接双指针前缀和,就不用树状数组了。

    Code
    #include <set>
    #include <cstdio>
    #define abs(a) ({int xx = a; xx < 0 ? -xx : xx;})
    
    const int N = 1e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >= '0' && c <= '9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    std::set<int> s;
    std::set<int>::iterator it1, it2;
    int n, m, f[N], siz[N], b[N], size;
    long long ans;
    
    int Find(int x) {
        return x == f[x] ? x : (f[x] = Find(f[x]));
    }
    
    int main() {
        freopen("cards.in", "r", stdin);
        freopen("cards.out", "w", stdout);
        n = read(); m = read();
        for (int i = 1; i <= n; ++i)
            f[i] = i, siz[i] = 1;
        size = b[1] = n;
        s.insert(1);
        while (m--) {
            int od = read();
            if (od == 1) {
                int x = Find(read()), y = Find(read());
                if (x == y) continue;
                if (!--b[siz[x]]) s.erase(siz[x]);
                if (!--b[siz[y]]) s.erase(siz[y]);
                f[x] = y; siz[y] += siz[x];
                siz[x] = 0;
                if (!b[siz[y]]++) s.insert(siz[y]);
                size--;
            }
            else {
                int x = read(), sum = 0; ans = 0;
                if (!x) {
                    printf("%lld
    ", 1LL * size * (size - 1) / 2);
                    continue;
                }
                it1 = it2 = s.begin();
                for (; it2 != s.end(); ++it2) {
                    while (it1 != s.end() && *it1 + x <= *it2) sum += b[*it1++];
                    /*if (*it1 + x <= *it2) */ans += 1LL * sum * b[*it2];
                }
                printf("%lld
    ", ans);
            }
        }
        return 0;
    }
    

    B Cicada 与排序 (Unaccepted)

    • 神奇的题,瞎搞了10分。



    联赛模拟测试24

    阶段排名 15

    本来就是靠T3拉分,结果它挂了80~90分,和第12差距70分,看来要回归最初的美好了。

    A 最大或

    • 就从前往后扫到一位不同的,后面就全是1就行了,挺好想的。
    Code
    #include <cstdio>
    #define int long long 
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >= '0' && c <= '9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    signed main() {
        freopen("maxor.in", "r", stdin);
        freopen("maxor.out", "w", stdout);
        int T = read();
        while (T--) {
            int l = read(), r = read(), s = 0;
            for (int i = 1LL << 59, g = 0; i; i >>= 1) {
                if (!(l & i) && (r & i)) g = 1;
                if (g || ((l & i) && (r & i))) s += i;
            }
            printf("%lld
    ", s);
        }
        return 0;
    }
    

    B 答题

    • 写的50分暴力只给了30分,出题人为了卡分连数据范围也不遵守了,我也是无fuck说了

    • 要知道的是题目的意思就是让求 n 个数组成的 (2^n) 个数第 (left lfloor p*(2^n) ight floor) 小的数

    • 正解是meet in the middle,先把前n/2个数组成的数记录下来,后面的数记录下来,二分第k小的数是多少,双指针查询就可以了

    Code
    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    
    typedef long long ll;
    const int N = 1.1e6;
    int n, a[45], f1[N], f2[N], s1, s2, n2, sum, l, r;
    double p;
    ll k;
    
    void Dfs1(int x, int s) {
        if (x > n2) return f1[++s1] = s, void();
        Dfs1(x + 1, s); Dfs1(x + 1, s + a[x]);
    }
    
    void Dfs2(int x, int s) {
        if (x > n) return f2[++s2] = s, void();
        Dfs2(x + 1, s); Dfs2(x + 1, s + a[x]);
    }
    
    bool Judge(int x, ll s = 0) {
        for (int i = 1, j = s2; i <= s1; ++i) {
            for (; j >= 1 && f1[i] + f2[j] > x; --j);
            if ((s += j) >= k) return 1;
        }
        return 0;
    }
    
    int main() {
        freopen("answer.in", "r", stdin);
        freopen("answer.out", "w", stdout);
        scanf("%d%lf", &n, &p);
        n2 = n / 2;
        k = ceil(p * (1LL << n));
        for (int i = 1; i <= n; ++i)
            scanf("%d
    ", &a[i]), r += a[i];
        Dfs1(1, 0); Dfs2(n2 + 1, 0);
        std::sort(f1 + 1, f1 + s1 + 1);
        std::sort(f2 + 1, f2 + s2 + 1);
        while (l < r) {
            int mid = l + r >> 1;
            if (Judge(mid)) r = mid;
            else l = mid + 1;
        }
        printf("%d
    ", l);
        return 0;
    }
    

    C 联合权值·改

    • 主要是求和的时候会被卡,剩下的都可过,可是for循环的时候v写的<=vecotr的size,然后就RE 5分,挂了80~90分

    • 就是一个三元环的问题,学会了n根号n不重复的枚举三元环就解决了,我连hash判联通都想到了,我和正解也就差个这个,加上就90了,

    • 90是因为本来时限1000的题让某队改成了200,到我交的时候改成了100,然后我有两个点99ms,使劲卡常A掉了

    Code
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #define re register
    
    typedef long long ll;
    const int N = 3e4 + 5, M = 59999;
    
    int read(re int x = 0, re int f = 1, re char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    std::vector<int> t[N], e[N];
    struct Hash {
        int next, x, y;
    }h[N<<1];
    int head[N<<1], hac;
    
    void Add(int x, int y) {
        t[x].push_back(y);
        int ha = (x * N + y) % M;
        h[++hac] = (Hash) {head[ha], x, y};
        head[ha] = hac;
    }
    
    bool Find(int x, int y) {
        int ha = (x * N + y) % M;
        for (re int i = head[ha]; i; i = h[i].next)
            if (h[i].x == x && h[i].y == y)
                return 1;
        return 0;
    }
    
    int n, m, a[N], od, in[N], mx;
    long long s;
    
    bool Cmp(const int &x, const int &y) {
        return a[x] > a[y];
    }
    
    int main() {
        freopen("link.in", "r", stdin);
        freopen("link.out", "w", stdout);
        n = read(), m = read(); od = read();
        while (m--) {
            int x = read(), y = read();
            Add(x, y); Add(y, x);
            in[x]++, in[y]++;
        }
        for (re int i = 1; i <= n; ++i)
            a[i] = read();
        for (re int x = 1; x <= n; ++x) {
            for (re int i = 0; i < t[x].size(); ++i) {
                int y = t[x][i];
                if (in[y] > in[x] || (in[y] == in[x] && y > x))
                    e[x].push_back(y);
            }
        }
        for (re int x = 1; x <= n; ++x) {
            if (t[x].size() < 2) continue;
            if (od != 2) {
                std::sort(t[x].begin(), t[x].end(), Cmp);
                int w = a[t[x][0]], w2 = 0;
                for (re int i = 1; i < t[x].size(); ++i)
                    if (!Find(t[x][0], t[x][i]))
                        w2 = a[t[x][i]], i = t[x].size();
                if ((w *= w2) > mx) mx = w;
            }
            if (od != 1) {
                ll s1 = 0, s2 = 0;
                for (re int i = 0; i < t[x].size(); ++i)
                    s1 += a[t[x][i]], s2 += a[t[x][i]] * a[t[x][i]];
                s += s1 * s1 - s2;
                for (re int i = 0; i < e[x].size(); ++i) {
                    int y = e[x][i];
                    for (re int j = 0; j < e[y].size(); ++j) {
                        int z = e[y][j];
                        if (!Find(x, z)) continue;
                        s -= 2LL * a[x] * a[y] + 2LL * a[x] * a[z] + 2LL * a[y] * a[z];
                    }
                }
            }
        }
        printf("%d
    %lld
    ", mx, s);
        return 0;
    }
    

    D 你相信引力吗

    • 不会写,就写了个30分n2暴力。

    • 首先可以想到一个冰锥会和两边不降的冰锥,直到第一个高于自己的冰锥构成危险冰锥对

    • 求危险冰锥对数,那就只计算前面的冰锥,那显然维护一个单调不升的单调栈就可以了

    • 题目中还提到是环,考虑不可能跨过最高点造成贡献,就直接从最高点断开计算

    • 还有重复的情况,就另开一个数组记录之前与当前高度相同的数量

    Code
    #include <cstdio>
    
    const int N = 5e6 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    int n, mx, a[N<<1], stk[N], s[N], tp;
    long long ans;
    
    int main() {
        freopen("jolyne.in", "r", stdin);
        freopen("jolyne.out", "w", stdout);
        n = read();
        for (int i = 1; i <= n; ++i) {
            a[i] = a[i+n] = read();
            if (a[i] > a[mx]) mx = i;
        }
        stk[tp=1] = a[mx];
        s[1] = 1;
        for (int i = mx + 1; i <= mx + n - 1; ++i) {
            for (; tp && stk[tp] < a[i]; --tp) ans++;
            if (stk[tp] == a[i]) ans += s[tp] + (a[i] != a[mx]);
            else ans++;
            stk[++tp] = a[i];
            s[tp] = a[i] == stk[tp-1] ? s[tp-1] + 1 : 1;
        }
        for (; tp > 2 && stk[tp] != stk[2]; --tp) ans++;
        printf("%lld
    ", ans);
        return 0;
    }
    

    联赛模拟测试23

    阶段排名 15

    A 数列

    • 一眼就是扩展欧几里得,可是忘了咋算,就yy了个逆元求出x,y的一组解,可是找不到绝对值和最小的解,就拿了30分

    • 在a<b的情况求出特解后让x尽可能接近0即可


    B 数对

    • 本来打的n3的,拿了0分,考完发现理解错题了,上次就是什么数对理解错了,这次又理解错了,信息奥赛考数学就算了吧,还考语文?强烈谴责出题人这种描述不清题目的行为!!

    • 先对序列按a+b的值排序在进行DP

    • 首先考虑n2的DP,f[i][j]表示考虑前i个元素,a的最大值为j的最大价值

        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                f[i][j] = std::max(f[i][j], f[i-1][j]);
                if (a[i].b >= j) f[i][std::max(j, a[i].a)] = std::max(f[i][std::max(j, a[i].a)], f[i-1][j] + a[i].w);
                ans = std::max(ans, f[i][j]);
            }
        }
    
    • 这样只有60分。考虑优化。

    • 可以每次发现需要修改的值不多,每次只有f[i][a[i]]会被修改最大值,还有f[i][a[i]]~f[i][b[i]]的值会加上w[i],、

    • 就写一颗支持最大值查询,区间加,单点修改的线段树即可

    Code
    #include <cstdio>
    #include <algorithm>
    #define ls (rt << 1)
    #define rs (rt << 1 | 1)
    
    typedef long long ll;
    const int N = 1e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Node {
        int a, b, w;
        bool operator < (const Node &y) const {
            return a + b < y.a + y.b;
        }
    }a[N];
    int n, b[N<<1], m;
    ll t[N<<3], tag[N<<3];
    
    void Pushdown(int rt) {
        t[ls] += tag[rt];
        t[rs] += tag[rt];
        tag[ls] += tag[rt];
        tag[rs] += tag[rt];
        tag[rt] = 0;
    }
    
    ll Ask(int rt, int l, int r, int x, int y) {
        if (x > r || y < l) return 0;
        if (x <= l && r <= y) return t[rt];
        if (tag[rt]) Pushdown(rt);
        int mid = l + r >> 1;
        return std::max(Ask(ls, l, mid, x, y), Ask(rs, mid + 1, r, x, y));
    }
    
    void Add(int rt, int l, int r, int x, int y, int w) {
        if (x > r || y < l) return;
        if (x <= l && r <= y) return t[rt] += w, tag[rt] += w, void();
        if (tag[rt]) Pushdown(rt);
        int mid = l + r >> 1;
        Add(ls, l, mid, x, y, w);
        Add(rs, mid + 1, r, x, y, w);
        t[rt] = std::max(t[ls], t[rs]);
    }
    
    void Change(int rt, int l, int r, int x, ll w) {
        if (l == r) return t[rt] = std::max(t[rt], w), void();
        if (tag[rt]) Pushdown(rt);
        int mid = l + r >> 1;
        if (x <= mid) Change(ls, l, mid, x, w);
        else Change(rs, mid + 1, r, x, w);
        t[rt] = std::max(t[ls], t[rs]);
    }
    
    int main() {
        freopen("pair.in", "r", stdin);
        freopen("pair.out", "w", stdout);
        n = read();
        for (int i = 1; i <= n; ++i) {
            a[i].a = b[++m] = read();
            a[i].b = b[++m] = read();
            a[i].w = read();
        }
        std::sort(b + 1, b + m + 1);
        m = std::unique(b + 1, b + m + 1) - b - 1;
        for (int i = 1; i <= n; ++i) {
            a[i].a = std::lower_bound(b + 1, b + m + 1, a[i].a) - b;
            a[i].b = std::lower_bound(b + 1, b + m + 1, a[i].b) - b;
        }
        std::sort(a + 1, a + n + 1);
        for (int i = 1; i <= n; ++i) {
            ll mx = Ask(1, 1, m, 1, std::min(a[i].a, a[i].b));
            Add(1, 1, m, a[i].a, a[i].b, a[i].w);
            Change(1, 1, m, a[i].a, mx + a[i].w);
        }
        printf("%lld
    ", t[1]);
        return 0;
    }
    

    C 最小距离

    • 我们的姚队实在是钛聚辣!!我再次用暴力碾过了正解,我跑三千多毫秒,有好几个正解跑了四、五千毫秒

    • 一眼就是原题,除了跑多源最短路没想到,其他的都还有些印象,然后就只能对每个特殊点都跑一遍dij了,没想到A了,交到原来的题上只有15分。

    • 以所有特殊点为起点跑多源最短路,并记录每个点是由那个点更新的,然后枚举每条边,如果两端点的起点不一样,就更新这两个起点的答案。

    Code
    #include <queue>
    #include <cstdio>
    #include <cstring>
    
    typedef long long ll;
    const int N = 2e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Edge {
        int next, t, d;
    }e[N<<1];
    int head[N], edc;
    
    void Add(int x, int y, int z) {
        e[++edc] = (Edge) {head[x], y, z};
        head[x] = edc;
    }
    
    std::priority_queue< std::pair<ll, int> > q;
    int n, m, p, a[N], c[N];
    ll d[N], ans[N];
    bool v[N];
    
    int main() {
        freopen("mindis.in", "r", stdin);
        freopen("mindis.out", "w", stdout);
        n = read(), m = read(); p = read();
        memset(d, 0x3f, 4 * n + 4);
        memset(ans, 0x3f, 4 * n + 4);
        for (int i = 1; i <= p; ++i) {
            a[i] = read();
            c[a[i]] = a[i];
            q.push(std::make_pair(d[a[i]] = 0, a[i]));
        }
        while (m--) {
            int x = read(), y = read(), z = read();
            Add(x, y, z); Add(y, x, z);
        }
        while (!q.empty()) {
            int x = q.top().second; q.pop();
            if (v[x]) continue;
            v[x] = 1;
            for (int i = head[x]; i; i = e[i].next) {
                int y = e[i].t;
                if (d[y] > d[x] + e[i].d) {
                    d[y] = d[x] + e[i].d;
                    c[y] = c[x];
                    q.push(std::make_pair(-d[y], y));
                }
            }
        }
        for (int i = 1; i <= edc; i += 2) {
            int x = e[i].t, y = e[i+1].t;
            ll dis = d[x] + d[y] + e[i].d;
            x = c[x], y = c[y];
            if (x == y) continue;
            ans[x] = std::min(ans[x], dis);
            ans[y] = std::min(ans[y], dis);
        }
        for (int i = 1; i <= p; ++i)
            printf("%lld ", ans[a[i]]);
        return 0;
    }
    

    D 真相 (Unaccepted)

    • 由于T1肝了2小时,导致我实在是没时间了,就rand了一下,拿了0分



    联赛模拟测试22

    阶段排名23

    A 求和

    • 式子很显然,就是等差数列求和,主要是会爆longlong,就得用点别的方法

    • 公式里有除以2,逆元不是很好算,所以就改成先除后龟速乘。


    B 分组配对

    • 本来想二分一下,算了算复杂度(O(n^2log^2n)),就写了个n方暴力,拿了60分

    • 很显然的两个贪心,组内的最大实力值是大的乘大的,小的乘小的,然后能放进组里就放,放不进就开了新组

    • 用倍增优化二分,先判断组长为(2^1,2^2,...)是否满足,到(2^x)时不满足时,就在(2^{x-1}~2^x)区间内二分长度(我二分的是右端点)

    Code

    Show Code
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    const int N = 5e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    int n, ans, a[N], b[N], sa[N], sb[N];
    long long m;
    
    bool Judge(int l, int r) {
        memcpy(sa + l, a + l, 4 * (r - l + 1));
        memcpy(sb + l, b + l, 4 * (r - l + 1));
        std::sort(sa + l, sa + r + 1);
        std::sort(sb + l, sb + r + 1);
        long long s = 0;
        for (int i = l; i <= r; ++i)
            if ((s += 1LL * sa[i] * sb[i]) > m)
                return 0;
        return 1;
    }
    
    int main() {
        freopen("pair.in", "r", stdin);
        freopen("pair.out", "w", stdout);
        n = read();
        scanf("%lld", &m);
        for (int i = 1; i <= n; ++i)
            a[i] = read();
        for (int i = 1; i <= n; ++i)
            b[i] = read();
        int x = 1;
        while (x <= n) {
            int i, l = 0, r;
            for (i = 2; x + i - 1 <= n; i <<= 1) {
                if (Judge(x, x + i - 1)) continue;
                l = x + i / 2 - 1, r = x + i - 1;
                break;
            }
            if (!l) l = x + i / 2 - 1, r = n;
            while (l < r) {
                int mid = l + r + 1 >> 1;
                if (Judge(x, mid)) l = mid;
                else r = mid - 1;
            }
            x = l + 1;
            ans++;
        }
        printf("%d
    ", ans);
        return 0;
    }
    

    C 城市游戏 (Unaccepted)

    • 看错题了,只拿了15分

    D 简单计算

    • 考场上没仔细想,拿了50分就走了。‘

    • 正解就是考虑向下取整会比原来少多少

    1LL * (n + 1) * m - n + Gcd(n, m) >> 1



    联赛模拟测试21

    阶段排名 28

    A 小盆友的游戏

    • T1就是期望题,直接puts("0"),虽然给了5个样例但还是没发毛线关系

    • 正解是构造函数(f_x=2^x-1),设整个局面的函数值为所有人函数值之和

    • 发现每猜一次拳局面的函数值的变化量都是1

    • 所以猜拳的次数就是最终局面的函数值与开始局面的函数值的差

    B 花

    • 写的暴力实在是太暴力了,于是它T成0分了

    • 定义f[i][0/1]前i个位置的方案数,0表示还没有出现连续3个的情况,1相反。转移方程

    [f_{i, 0}=f_{i-1, 0}*(s-1)+f_{i-2, 0}*(s-1) ]

    [f_{i, 1}=f_{i-1, 1}*(s-1)+f_{i-2, 1}*(s-1)+f_{i-3,0}*(s-1) ]

    C 表格 (Unaccepted)

    • 开始YY了一个50分写法,结果跑的比暴力还慢,最后就只有10分,不过整个机房最高分也就是10分了

    D 格式化

    • 显然需要贪心排序,由于实在是太菜了,就没想出来,写了50分部分分然后用random_shuffle拿了15分。

    • 先放使容量增加的,再放容量不变的,最后放使容量减小的

    • 对于容量增加的,先放格式化之前小的

    • 对于容量减小的,先放格式化之后大的


  • 相关阅读:
    Oracle函数如何把符串装换为小写的格式
    Oralce中的synonym同义词
    JS中getYear()的兼容问题
    How to do SSH Tunneling (Port Forwarding)
    所谓深度链接(Deep linking)
    upload size of asp.net
    发一个自动刷网站PV流量的小工具
    解决Visual Studio 2008 下,打开.dbml(LINQ) 文件时,提示"The operation could not be completed." 的问题。
    在资源管理器中使鼠标右键增加一个命令,运行cmd,同时使得当前路径为资源管理器当前的目录
    使用SQL语句获取Sql Server数据库的版本
  • 原文地址:https://www.cnblogs.com/shawk/p/13864230.html
Copyright © 2011-2022 走看看