zoukankan      html  css  js  c++  java
  • 省选测试1

    省选测试1

    T1

    ​ 给定长度为(n)的排列,(m)个询问.每次询问区间([l,r])中,最长的值域连续的一段.

    ​ 最长的值域连续的一段是指从排列的([l,r])的区间中选出一些数, 使得这些数排序后构成了连续的一段正整数, 那么这些正整数就是一个值域连续段.

    (n, m <= 5e4)

    ​ 回滚莫队 + 并查集.

    ​ 很显然莫队可做, 但是考试的时候并没有学过回滚莫队, 于是就用了普通莫队 + 线段树搞了一个(O(nsqrt n logn))的做法.

    ​ 我们发现这道题的难点就在于如何删除一个数字的影响. 那我们可以考虑只有加入操作没有删除操作. 这正好就是回滚莫队了.

    ​ 那么回滚莫队是什么呢? 其实就是莫队 + 栈.我们把加入数字时每一个影响都加入到栈中, 然后回滚的时候弹栈消除影响.

    ​ 首先, 对于左右区间在同一个快内的询问直接暴力查就好了.

    ​ 然后考虑怎么加入一个数的影响. 直接并查集合并就好了, 维护一个集合的大小(siz).

    ​ 我们找出左端点在同一个块(x)内的询问. 对于右端点, 我们已经排好序了, 是递增的, 所以只存在加入操作.对于左端点, 我们每次把左指针都回滚块(x)的右端点, 然后左移左端点, 也是只有加入操作.

    ​ 总结一下 : 右端点不断向右移, 左端点总是左移,回滚,左移,回滚......由于左端点所在块的大小为(sqrt n)的, 所以和一般莫队相比也只是乘上了2的常数.总的复杂度为(O(n sqrt n alpha)).有一个并查集的常数.

    #include <bits/stdc++.h>
    
    #define rei register int
    
    using namespace std;
    
    inline int read() {
        int s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 5e4 + 5, M = 250;
    int n, m, top, res, top1;
    int a[N], L[N], R[N], fa[N], siz[N], vis[N], pos[N], ans[N], tnp[M];
    struct ques { int l, r, id; } q[N];
    struct stack { int opt, x, y; } sta[N << 3], sta1[N << 3];
    
    int cmp(ques x, ques y) {
        return pos[x.l] == pos[y.l] ? x.r < y.r : pos[x.l] < pos[y.l];
    }
    
    int find(int x) {
        return x == fa[x] ? x : find(fa[x]);
    }
    
    void add(int x) {
        vis[a[x]] = 1;
        sta1[++ top1].opt = 1; sta1[top1].x = a[x];
        if(vis[a[x] - 1]) {
            int fx = find(a[x]), fy = find(a[x] - 1);
            if(siz[fy] < siz[fx]) swap(fx, fy);
            sta1[++ top1].opt = 2; sta1[top1].x = fx;
            fa[fx] = fy; 
            sta1[++ top1].opt = 3; sta1[top1].x = fy; sta1[top1].y = siz[fy];
            siz[fy] += siz[fx];
            res = max(res, siz[fy]);
            // cout << a[x] - 1 << " " << fy << " " << siz[fy] << "^^^
    ";
        }
        if(vis[a[x] + 1]) {
            int fx = find(a[x]), fy = find(a[x] + 1);
            if(siz[fy] < siz[fx]) swap(fx, fy);
            sta1[++ top1].opt = 2; sta1[top1].x = fx;
            fa[fx] = fy; 
            sta1[++ top1].opt = 3; sta1[top1].x = fy; sta1[top1].y = siz[fy];
            siz[fy] += siz[fx];
            res = max(res, siz[fy]);
        }
    }
    
    void add_(int x) {
        // cout << a[x] << "------>
    ";
        vis[a[x]] = 1;
        sta[++ top].opt = 1; sta[top].x = a[x];
        if(vis[a[x] - 1]) {
            // cout << "---
    ";
            int fx = find(a[x]), fy = find(a[x] - 1);
            if(siz[fy] < siz[fx]) swap(fx, fy); 
            sta[++ top].opt = 2; sta[top].x = fx; 
            fa[fx] = fy;
            sta[++ top].opt = 3; sta[top].x = fy; sta[top].y = siz[fy];
            // cout << siz[fy] << " " << siz[fx] << ")))
    ";
            siz[fy] += siz[fx];
            res = max(res, siz[fy]);
            // cout << res << "
    ";
        }
        if(vis[a[x] + 1]) { 
            // cout << "+++
    ";
            int fx = find(a[x]), fy = find(a[x] + 1);
            if(siz[fy] > siz[fx]) swap(fx, fy);
            sta[++ top].opt = 2; sta[top].x = fx;
            fa[fx] = fy;
            sta[++ top].opt = 3; sta[top].x = fy; sta[top].y = siz[fy];
            siz[fy] += siz[fx];
            res = max(res, siz[fy]);
            // cout << res << "
    ";
        }
    }
    
    void Pop_() {
        if(sta[top].opt == 0) res = sta[top].x, top --;
        if(sta[top].opt == 1) vis[sta[top].x] = 0, top --;
        if(sta[top].opt == 2) fa[sta[top].x] = sta[top].x, top --;
        if(sta[top].opt == 3) siz[sta[top].x] = sta[top].y, top --;
    }
    
    void Pop() {
        if(sta1[top1].opt == 0) res = sta1[top1].x, top1 --;
        if(sta1[top1].opt == 1) vis[sta1[top1].x] = 0, top1 --;
        if(sta1[top1].opt == 2) fa[sta1[top1].x] = sta1[top1].x, top1 --;
        if(sta1[top1].opt == 3) siz[sta1[top1].x] = sta1[top1].y, top1 --;
    }
    
    int main() {
    
        freopen("permu.in","r",stdin); freopen("permu.out","w",stdout);
    
        n = read(); m = read(); int B = sqrt(n);
        for(int i = 1;i <= n; i++) fa[i] = i, siz[i] = 1; res = 1;
        for(int i = 1;i <= n; i++) L[i] = 2333333;
        for(rei i = 1;i <= n; i++) a[i] = read(), pos[i] = (i - 1) / B + 1;
        for(int i = 1;i <= n; i++) L[pos[i]] = min(L[pos[i]], i), R[pos[i]] = max(R[pos[i]], i);
        for(rei i = 1;i <= m; i++) q[i].l = read(), q[i].r = read(), q[i].id = i;
        // for(int i = 1;i <= n; i++) cout << pos[i] << " "; cout << "
    ";
        sort(q + 1, q + m + 1, cmp);
        // for(int i = 1;i <= m; i++) cout << q[i].l << " " << q[i].r << " " << q[i].id << "
    ";
        rei x, y;
        for(rei i = 1, j;i <= m; i = j) {
            int now_k = pos[q[i].l];
            x = R[now_k] + 1; y = R[now_k];
            // cout << x << " " << y << " " << res << "
    ";
            sta1[++ top1].opt = 0; sta1[top1].x = res;
            for(j = i;pos[q[j].l] == now_k; j++) {
                if(pos[q[j].r] == pos[q[j].l]) {
                    // cout << q[j].l << " " << q[j].r << "!!!
    ";
                    int cnt = 0;
                    for(int k = q[j].l;k <= q[j].r; k++) tnp[++ cnt] = a[k];
                    sort(tnp + 1, tnp + cnt + 1);
                    int cop = 1, cip = 1;
                    for(int k = 2;k <= cnt; k++)  
                        if(tnp[k] == tnp[k - 1] + 1) cop ++, cip = max(cip, cop);
                        else cop = 1;
                    ans[q[j].id] = cip;
                }
                else {
                    // cout << q[j].l << " " << q[j].r << ")))
    ";
                    while(y < q[j].r) add(++ y);
                    // cout << j << ":" << res << "!!!
    ";
                    sta[++ top].opt = 0; sta[top].x = res;
                    while(x > q[j].l) add_(-- x);
                    ans[q[j].id] = res;
                    while(top) Pop_();
                    x = R[now_k] + 1;
                }
            }
            while(top1) Pop();
        }
        for(rei i = 1;i <= m; i++) printf("%d
    ", ans[i]);
    
        fclose(stdin); fclose(stdout);
    
        return 0;
    }
    
    /*
    8 3
    3 1 7 2 5 8 6 4
    1 4
    5 8
    1 7
    */
    

    (上面代码写的太麻烦了, 其实好多东西都可以合并到一起去的).

    T2

    ​ 有一颗(n)个点的树, 有三个点在树上轮流取点,直到点被取完.

    ​ 取完之后需要计算每一个人的得分.有(m)个幸运数, 对于一个点对((u, v)), 如果它们在原图上的距离为一个幸运数, 并且被同一个人取到, 那么这个人就得到一分.

    ​ 假设每个人取点时都是等概率的选取一个未被选过的点, 问每个人得分的期望.

    (n <= 5e4, m <= 10).

    ​ 点分治.

    ​ (考场上完全没有思路啊)

    ​ 对于每个人其实都是可以分开算的, 因为选取每个点的概率都是相等的.

    ​ 假设一个人需要选择(k)个点, 那么总共就有(C_n^k)中方案, 对于某一个点对的选取概率是 : (frac{C_{n-2}^{k-2}}{C_n^k} = frac{k*(k-1)}{n*(n-1)}).意思就是当前的点对已经选好了, 剩下(k-2)个点随便选.

    ​ 每一个点对的概率都是这样的, 所以现在问题转化成了, 计算有多少个点对的距离为幸运数, 那么直接点分治就好了, 复杂度(O(mnlogn)).

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }   
    
    const int N = 5e4 + 5;
    int n, m, rt, cnt, totsiz;
    int k[11], dis[N], tmp[N], siz[N], num[N], vis[N], head[N], tong[N], Tmp[N], Tong[N], maxsiz[N];
    struct edge { int to, nxt; } e[N << 1];
    
    void add(int x, int y) {
        e[++ cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y;
    }
    
    void get_rt(int x, int fa) {
        siz[x] = 1; maxsiz[x] = 0;
        for(int i = head[x]; i ; i = e[i].nxt) {
            int y = e[i].to; if(vis[y] || y == fa) continue ;
            get_rt(y, x); siz[x] += siz[y];
            maxsiz[x] = max(maxsiz[x], siz[y]);
        }
        maxsiz[x] = max(maxsiz[x], totsiz - siz[x]);
        if(maxsiz[rt] > maxsiz[x]) rt = x;
    }
    
    void get_dis(int x, int fa) {
        if(!tong[dis[x]] && dis[x]) tmp[++ cnt] = dis[x];
        tong[dis[x]] ++;
        for(int i = head[x]; i ; i = e[i].nxt) {
            int y = e[i].to; if(y == fa || vis[y]) continue ;
            dis[y] = dis[x] + 1;
            get_dis(y, x);
        }
    }
    
    void calc(int x) {
        // cout << x << "--------->
    ";
        int Cnt = 0; dis[x] = 0;
        for(int ii = head[x]; ii ; ii = e[ii].nxt) {
            int y = e[ii].to; if(vis[y]) continue ;
            dis[y] = dis[x] + 1;
            for(int i = 1;i <= cnt; i++) tong[tmp[i]] = 0; cnt = 0;
            get_dis(y, x); 
            sort(tmp + 1, tmp + cnt + 1);
            // cout << y << "---->
    ";
            // for(int i = 1;i <= cnt; i++) cout << tmp[i] << " "; cout << "
    "; 
            // for(int i = 1;i <= cnt; i++) cout << tong[tmp[i]] << " "; cout << "
    ";
            for(int i = 1;i <= m; i++) {
                num[i] += tong[k[i]];
                for(int j = 1;j <= cnt; j++) { 
                    if(tmp[j] >= k[i]) break ;
                    num[i] += tong[tmp[j]] * Tong[k[i] - tmp[j]];
                }
                // cout << i << ":" << num[i] << "
    ";
            }
            for(int i = 1;i <= cnt; i++) {
                if(!Tong[tmp[i]]) Tmp[++ Cnt] = tmp[i];
                Tong[tmp[i]] += tong[tmp[i]];
            }
        }
        for(int i = 1;i <= Cnt; i++) Tong[tmp[i]] = tong[tmp[i]] = 0;
    }
    
    void solve(int x) {
        calc(x); vis[x] = 1;
        for(int i = head[x]; i ; i = e[i].nxt) {
            int y = e[i].to; if(vis[y]) continue ;
            maxsiz[0] = totsiz = siz[y]; rt = 0;
            get_rt(y, 0); solve(rt);
        }
    }
    
    int t[4];
    void calc_sum(int x) {
        double k_ = 1.0 * t[x] * (t[x] - 1) / (1.0 * n * (n - 1)), sum = 0;
        for(int i = 1;i <= m; i++) sum += k_ * num[i];
        printf("%.2lf
    ", sum);
    }
    
    int main() {
    
        freopen("game.in","r",stdin); freopen("game.out","w",stdout);
    
        n = read(); m = read();
        for(int i = 1;i <= m; i++) k[i] = read();
        for(int i = 1, x, y;i < n; i++) {
            x = read(); y = read(); add(x, y); add(y, x);
        }
        maxsiz[0] = totsiz = n; rt = 0;
        get_rt(1, 0); solve(rt);
        // for(int i = 1;i <= m; i++) cout << i << ":" << k[i] << " " << num[i] << "
    ";
        int t1 = n / 3, t2 = n % 3;
        if(t2 == 0) t[1] = t[2] = t[3] = t1;
        if(t2 == 1) t[1] = t1 + 1, t[2] = t[3] = t1;
        if(t2 == 2) t[1] = t[2] = t1 + 1, t[3] = t1;
        for(int i = 1;i <= 3; i++) calc_sum(i);
    
        fclose(stdin); fclose(stdout);
    
        return 0;
    }
    
    /*
    5 3
    1 2 3
    1 2
    1 5
    2 3
    2 4
    */
    

    T3

    ​ 给定一张(n)个点的无向图, 要求把(n)个点都分入(A, B)集合中.

    ​ 若点(i, j)不相连, 则(i, j)不可以同时放入(A)集合中;

    ​ 若点(i, j)相连,则(i, j)不可以同时放入(B)集合中;

    (A, B)集合都不可以为空.

    ​ (相连是指有直接连边)

    ​ 问有多少种方案可以满足上面的条件.

    (n <= 5000).

    ​ 2-sat.

    ​ 一个点只能有两种选择, 显然2-sat.

    ​ 如果两个点(x,y)相连, 那么连((x+n ightarrow y), (y+n ightarrow x)).

    ​ 如果两个点(x, y)不相连, 那么连((x ightarrow y + n)(y ightarrow x +n)).

    ​ 然后跑Tarjan判断有无解.

    ​ 主要是怎么找到所有方案.

    ​ 首先找到一个初始方案, 我们发现要得到其他方案只有这三种方式:

    ​ 1.找一个(A)集合中的点(x)放到(B)集合, 条件是与(x)相连的所有点都不可以在(B)集合.

    ​ 2.找一个(B)集合中的点(y)放到(A)集合, 条件是与(y)不相连的所有点都不可以在(A)集合.

    ​ 3.找一个(A)集合中的点(x)(B)集合中的点(y), 把它们交换, 条件是除了(y)所有与(x)相连的点都不可以在(B)集合, 除了(x)所有与(y)不相连的点都不可以在(A)集合.

    ​ 为什么只有这三种情况呢? 假设我们要从(A)集合移动两个点到(B)集合, 那么这两个点一定是有直接连边的, 那么它们就不能同时存在于(B)集合.所以不管移动那个集合, 一定是只能移动一个点的.

    ​ 记得最后判断一下(A, B)不为空就好了.

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 5005, M = 3e7;
    int n, cnt, tot, top, css, siz1, siz2;
    int in[N << 1], col[N << 1], dfn[N << 1], sta[N << 1], low[N << 1], head[N << 1], inse[N], link[N][N];
    struct edge { int to, nxt; } e[M];
    vector <int> v[N];
    
    void add(int x, int y) {
        e[++ cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y;
    }
    
    void Tarjan(int x) {
        dfn[x] = low[x] = ++ tot; in[x] = 1; sta[++ top] = x;
        for(int i = head[x]; i ; i = e[i].nxt) {
            int y = e[i].to; 
            if(!dfn[y]) Tarjan(y), low[x] = min(low[x], low[y]);
            else if(in[y]) low[x] = min(low[x], dfn[y]);
        }
        if(dfn[x] == low[x]) {
            int p; css ++;
            do {
                in[p = sta[top --]] = 0;
                col[p] = css;
            } while(p != x);
        }
    }
    
    void Sta_pro() {
        int ans;
        if(siz1 == 0 || siz2 == 0) ans = 0; // ***
        else ans = 1;
        for(int x = 1;x <= n; x++) {
            if(!inse[x] && siz1 > 1) { // ***
                int f = 0;
                for(int i = 0;i < (int) v[x].size(); i++)
                    if(inse[v[x][i]]) { f = 1; break; }
                if(!f) ans ++;
            }
            if(inse[x] && siz2 > 1) { // ***
                int f = 0;
                for(int y = 1;y <= n; y++) {
                    if(y == x || link[x][y]) continue ;
                    if(!inse[y]) { f = 1; break ; } 
                }
                if(!f) ans ++;
            }
        }
        for(int x = 1;x <= n; x++) 
            for(int y = 1;y <= n; y++) 
                if(!inse[x] && inse[y]) {
                    int f = 0;
                    for(int i = 0;i < (int) v[x].size(); i++) 
                        if(inse[v[x][i]] && v[x][i] != y) { f = 1; break ; }
                    if(f) continue ;
                    for(int z = 1;z <= n; z++) {
                        if(z == x || z == y || link[z][y]) continue ;
                        if(!inse[z]) { f = 1; break ; }
                    }
                    if(!f) ans ++;
                }
        printf("%d", ans);
    }
    
    void Work2() {
        for(int i = 1;i <= n; i++)
            for(int j = i + 1;j <= n; j++) 
                if(link[i][j]) add(i + n, j), add(j + n, i);
                else add(i, j + n), add(j, i + n);
        for(int i = 1;i <= 2 * n; i++) if(!dfn[i]) Tarjan(i);
        // for(int i = 1;i <= n; i++) cout << i << ":" << col[i] << " " << col[i + n] << "
    ";
        for(int i = 1;i <= n; i++) if(col[i] == col[i + n]) {
            printf("0"); return ;
        }
        for(int i = 1;i <= n; i++) inse[i] = col[i] < col[i + n] ? 0 : 1;
        for(int i = 1;i <= n; i++) 
            if(!inse[i]) siz1 ++;
            else siz2 ++;
        // for(int i = 1;i <= n; i++) cout << i << ":" << inse[i] << "
    ";
        Sta_pro();
    }
    
    int main() {
    
        freopen("conspiracy.in","r",stdin); freopen("conspiracy.out","w",stdout);
    
        n = read();
        for(int i = 1, t;i <= n; i++) {
            t = read();
            for(int j = 1, x;j <= t; j++) 
                x = read(), v[i].push_back(x), link[i][x] = 1;
        }
        Work2();
    
        fclose(stdin); fclose(stdout);
    
        return 0;
    }
    
    /*
    4
    2 2 3
    2 1 3
    3 1 2 4
    1 3
    */
    
  • 相关阅读:
    HDU 2236 无题Ⅱ
    Golden Tiger Claw(二分图)
    HDU 5969 最大的位或 (思维,贪心)
    HDU 3686 Traffic Real Time Query System (图论)
    SCOI 2016 萌萌哒
    Spring Boot支持控制台Banner定制
    构建第一个Spring Boot程序
    Spring Boot重要模块
    Java fastjson JSON和String互相转换
    BCompare 4 Windows激活方法【试用期30天重置】
  • 原文地址:https://www.cnblogs.com/czhui666/p/14461635.html
Copyright © 2011-2022 走看看