zoukankan      html  css  js  c++  java
  • 「赛后总结」Codeforces Round #686 (Div. 3)

    题意 & 题解

    A.Special Permutation

    题意:

    找一个 (1sim n) 的排列使得 (forall i in[1,n])(a_i eq i)。多测。

    题解:

    小构造。

    (n) 为偶数,答案是 (nsim 1)

    (n) 为奇数,先输出中位数再 (nsim1)

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <algorithm>
    
    int t, n;
    
    int main() {
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            if (n & 1) {
                printf("%d ", n / 2 + 1);
                for (int i = n; i >= 1; --i) {
                    if (i == n / 2 + 1) continue;
                    printf("%d ", i);
                }
            }
            else {
                for (int i = n; i >= 1; --i) printf("%d ", i);
            }
            puts("");
        }
        return 0;
    }
    

    B.Unique Bid Auction

    题意:

    找到只出现过一次的最小的数的下标。多测。

    题解:

    将原数组排序后看是否出现过多次。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #define M 200010
    
    int t, n;
    struct qwer {
        int w, id;
        friend bool operator < (qwer q1, qwer q2) {
            return q1.w < q2.w;
        }
    }a[M];
    
    int main() {
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n); int ans = -1;
            for (int i = 1; i <= n; ++i) {
                scanf("%d", &a[i].w);
                a[i].id = i;
            }
            std::sort(a + 1, a + n + 1);
            for (int i = n; i >= 1; --i) {
                if (a[i].w != a[i + 1].w && a[i].w != a[i - 1].w) ans = a[i].id;
            }
            for (int i = 1; i <= n; ++i) {
                a[i].w = a[i].id = 0;
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    

    C.Sequence Transformation

    题意:

    给定一个序列,选择序列中一个数 (x),每次可以删除一段不含 (x) 的区间,问最少多少次序列中只剩下 (x)。多测。

    题解:

    题目其实就是问出现次数最少的数出现了多少次。连续的一段相同的数按一次算,两端的端点不算。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #define M 200001
    
    int min(int a, int b) { return a < b ? a : b; }
    
    int t, n, a[M], cnt[M];
    
    int main() {
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            memset(cnt, 0, sizeof cnt);
            for (int i = 1; i <= n; ++i) {
                scanf("%d", &a[i]);
                if (a[i] != a[i - 1]) ++cnt[a[i]];
            }
            --cnt[a[1]], --cnt[a[n]];
            int minn = 2147483647;
            for (int i = 1; i <= n; ++i) {
                minn = min(minn, cnt[a[i]]);
            }
            printf("%d
    ", minn + 1);
        }
        return 0;
    }
    

    D.Number into Sequence

    题意:

    给一个数 (n),要求找一个长为 (k) 的序列,使得 (forall iin [2,n])(a_{i-1}mid a_i) 并且 (prodlimits_{i=1}^{n} a_i = n)。要求 (k) 最大。多测。

    题解:

    根据唯一分解定理 (n) 一定可以写成下面的形式。

    (n = {p_1}^{q_1} imes {p_2}^{q_2} imes dots imes {p_n}^{q_n})

    如果没有 (forall iin [2,n])(a_{i-1}mid a_i) 这个要求直接输出每个质因子就是最长的。这个要求就使得下标小的元素含有的质因子,下标大的元素必须含有。所以最长的 (k) 就是 (maxlimits_{i=1}^{n} q_i)

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <algorithm>
    typedef long long ll;
    
    ll t, n;
    
    void solve(ll x) {
        ll k = 0, ans = x, temp = 1, stop = sqrt(x);
        for (int i = 2; i <= stop; ++i) {
            if (x % i == 0) {
                ll k_ = 0;
                while (x % i == 0) {
                    ++k_, x /= i;
                }
                if (k_ > k) k = k_, temp = i;
            }
        }
        if (k == 0) k = 1;
        printf("%d
    ", k);
        for (int i = 1; i < k; ++i) {
            printf("%lld ", temp);
            ans /= temp;
        }
        printf("%lld
    ", ans);
    }
    
    int main() {
        scanf("%lld", &t);
        while (t--) {
            scanf("%lld", &n);
            solve(n);
        }
        return 0;
    }
    

    E.Number of Simple Paths

    题意:

    给定 (n) 个点 (n) 条边的无向连通图,问其中有多少不同的简单路径。多测。

    题解:

    图是一个环上面挂着多颗树的样子。

    对于每颗树内的路径,设树的根节点为 (v),以 (v) 为根的子树的大小为 (cnt_v)(不包含环中除了 (v) 的其他点)。路径条数为 (dfrac{cnt_v(cnt_v-1)}{2})

    对于从树上走出去的路径条数有 (2 imes cnt_v(n-cnt_v)) 只用统计 (cnt_v(n-cnt_v)) 防止重复。

    统计 (cnt_v) 可以使用类似拓扑序的东西。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #define M 200001
    
    int cnt[M];
    std::queue<int> q;
    int t, n, pthn, head[M], ideg[M];
    struct Edge {
        int nxt, to;
    }pth[M << 1];
    
    void add(int frm, int to) {
        pth[++pthn].to = to, pth[pthn].nxt = head[frm];
        head[frm] = pthn;
    }
    
    void format() {
        for (int i = 1; i <= n; ++i) ideg[i] = 0;
        for (int i = 1; i <= n; ++i) head[i] = 0;
        for (int i = 1; i <= pthn; ++i) pth[i].nxt = pth[i].to = 0;
        pthn = 0;
    }
    
    int main() {
        scanf("%d", &t);
        while (t--) {
            format();
            scanf("%d", &n);
            for (int i = 1, u, v; i <= n; ++i) {
                scanf("%d %d", &u, &v);
                add(u, v), add(v, u);
                ++ideg[u], ++ideg[v];
            }
            for (int i = 1; i <= n; ++i) {
                cnt[i] = 1;
                if (ideg[i] == 1) q.push(i);
            }
            while (!q.empty()) {
                int u = q.front(); q.pop();
                for (int i = head[u]; i; i = pth[i].nxt) {
                    int v = pth[i].to;
                    if (ideg[v] != 1) {
                        --ideg[v], cnt[v] += cnt[u];
                        if (ideg[v] == 1) q.push(v);
                    }
                }
            }
            long long ans = 0;
            for (int i = 1; i <= n; ++i) {
                if (ideg[i] != 1) ans += 1ll * cnt[i] * (cnt[i] - 1) / 2 + 1ll * cnt[i] * (n - cnt[i]);
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    

    F.Array Partition

    题意:

    给一个序列 (a)。找到三个数 (x,y,z) 使得 (x+y+z = n) 并且 (maxlimits_{i=1}^{x}{a_i} = minlimits_{i=x+1}^{x+y}{a_i} = maxlimits_{i=x+y+1}^{n}{a_i})。要求 (x,y,z > 0)。多测。

    题解:

    枚举第一个区间的右端点 (x)(max1 = maxlimits_{i=1}^{x}{a_i})

    二分第二个区间的右端点 (mid)(min1 = minlimits_{i=x+1}^{mid}{a_i})

    如果 (max1>min1) 第二个区间需要缩小。

    如果 (max1<min1) 第二个区间需要扩大。

    如果 (max1 = min1) 去判断和第三个区间的关系,(max2 = maxlimits_{i=mid+1}^{n}{a_i})

    如果 (max2 = min1) 代表找到了答案。

    如果 (max2 > min1) 第二个区间需要扩大。

    如果 (max2 < min1) 第二哥区间需要缩小。

    查询最值使用 (st) 表。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #define M 200001
    
    inline void read(int &T) {
    	int x = 0;
    	bool f = 0;
    	char c = getchar();
    	while (c < '0' || c > '9') {
    		if (c == '-') f = !f;
    		c = getchar();
    	}
    	while (c >= '0' && c <= '9') {
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	T = f ? -x : x;
    }
    
    int min(int a, int b) { return a < b ? a : b; }
    int max(int a, int b) { return a > b ? a : b; }
    
    int t, n, lg[M], min_[M][21], max_[M][21];
    
    int qmax(int l, int r) {
    	int k = lg[r - l + 1] - 1;
    	return max(max_[l][k], max_[r - (1 << k) + 1][k]);
    }
    
    int qmin(int l, int r) {
    	int k = lg[r - l + 1] - 1;
    	return min(min_[l][k], min_[r - (1 << k) + 1][k]);
    }
    
    bool solve(int x, int &r) {
    	int l = x + 1, max1 = qmax(1, x); r = n - 1;
    	while (l <= r) {
    		int mid = (l + r) >> 1;
    		int min1 = qmin(x + 1, mid), max2 = qmax(mid + 1, n);
    		if (min1 == max1) {
    			if (max2 == min1) { r = mid; return true; }
    			if (max2 > min1) l = mid + 1;
    			if (max2 < min1) r = mid - 1;
    		}
    		if (min1 > max1) l = mid + 1;
    		if (min1 < max1) r = mid - 1;
    	}
    	return false;
    }
    
    int main() {
    	read(t);
    	for (int i = 1; i < M; ++i) {
    		lg[i] = lg[i - 1] + ((1 << lg[i - 1]) == i);
    	}
    	while (t--) {
    		read(n);
    		for (int i = 1, x; i <= n; ++i) {
    			read(x);
    			min_[i][0] = max_[i][0] = x;
    		}
    		for (int j = 1; (1 << j) <= n; ++j) {
    			for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
    				min_[i][j] = min(min_[i][j - 1], min_[i + (1 << (j - 1))][j - 1]);
    				max_[i][j] = max(max_[i][j - 1], max_[i + (1 << (j - 1))][j - 1]);
    			}
    		}
    		int l = -1, r = 0;
    		for (int i = 1; i < n - 1; ++i) {
    			if (solve(i, r)) { l = i; break; }
    		}
    		if (l == -1) puts("NO");
    		else {
    			puts("YES");
    			//std::cout << qmax(1, l) << " " << qmin(l + 1, r) << " " << qmax(r + 1, n) << '
    ';
    			printf("%d %d %d
    ", l, r - l, n - r);
    		}
    	}
    	return 0;
    }
    

    rating & 总结

    没有 rating。

    我不太行/kk

  • 相关阅读:
    vim 的列操作
    关于 matplotlib
    freemarker的常用内建函数
    三次握手与四次挥手
    layui动态表格生成
    layui 解决浏览器自动填充form表单账号和密码输入框的问题
    手机验证 和身份证验证
    把动态查询出来的集合数据,横向展示在页面
    eclipse安装freemarker插件
    目录文件树jQuery Ztree基本用法
  • 原文地址:https://www.cnblogs.com/poi-bolg-poi/p/14040269.html
Copyright © 2011-2022 走看看