• Codeforces Round #783 (Div. 2)


    A:从(1,1)移动至(n,m),每次可以往上下左右一个方向移动一次,不能连续两次往同一个方向移动,问是否可行及最少移动次数(solution略)

    B:给定n个人和m张椅子(组成环形),每个人要求左右都至少有\(A_i\)的空位不坐人,问是否能将n个人安顿在这m个座位上。

    \(A\)升序排序,贪心构造易得其需要的最少座位数为\(n+A_n+\sum\limits_{i=2}^nA_i\)

    /*program from Wolfycz*/
    #include<map>
    #include<set>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define Fi first
    #define Se second
    #define lMax 1e18
    #define MK make_pair
    #define iMax 0x7f7f7f7f
    #define sqr(x) ((x)*(x))
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    template<typename T>inline T read(T x) {
        int f = 1; char ch = getchar();
        for (; ch < '0' || ch>'9'; ch = getchar())	if (ch == '-')	f = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())	x = (x << 1) + (x << 3) + ch - '0';
        return x * f;
    }
    inline void print(int x) {
        if (x < 0)	putchar('-'), x = -x;
        if (x > 9)	print(x / 10);
        putchar(x % 10 + '0');
    }
    const int N = 2e5;
    int A[N + 10];
    int main() {
        int T = read(0);
        while (T--) {
            int n = read(0), m = read(0);
            for (int i = 1; i <= n; i++)  A[i] = read(0);
            sort(A + 1, A + 1 + n);
            ll res = A[n] + n;
            for (int i = 2; i <= n; i++)  res += A[i];
            printf(res <= m ? "YES\n" : "NO\n");
        }
        return 0;
    }
    

    C:给定序列\(A\),和空序列\(B\),每次操作可以让\(B_i+=A_i\),或者\(B_i-=A_i\),问最少需要几次操作可以让\(B\)严格升序?

    由于\(n\)较小,故我们可以考虑\(n^2\)做法,暴力枚举一个不动点(即\(B_i=0\)),再从\(i\)位置开始依次确定每个点保证严格升序所需的最小操作次数即可

    /*program from Wolfycz*/
    #include<map>
    #include<set>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define Fi first
    #define Se second
    #define lMax 1e18
    #define MK make_pair
    #define iMax 0x7f7f7f7f
    #define sqr(x) ((x)*(x))
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    template<typename T>inline T read(T x) {
        int f = 1; char ch = getchar();
        for (; ch < '0' || ch>'9'; ch = getchar())	if (ch == '-')	f = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())	x = (x << 1) + (x << 3) + ch - '0';
        return x * f;
    }
    inline void print(int x) {
        if (x < 0)	putchar('-'), x = -x;
        if (x > 9)	print(x / 10);
        putchar(x % 10 + '0');
    }
    const int N = 5e3;
    int A[N + 10], n;
    ll solve(int x) {
        ll res = 0, Now = 0;
        for (int j = x + 1; j <= n; j++) {
            res += Now / A[j] + 1;
            Now = 1ll * (Now / A[j] + 1) * A[j];
        }
        Now = 0;
        for (int j = x - 1; j; j--) {
            res += Now / A[j] + 1;
            Now = 1ll * (Now / A[j] + 1) * A[j];
        }
        return res;
    }
    int main() {
        n = read(0); ll Ans = lMax;
        for (int i = 1; i <= n; i++)  A[i] = read(0);
        for (int i = 1; i <= n; i++)  Ans = min(Ans, solve(i));
        printf("%lld\n", Ans);
        return 0;
    }
    

    D:给定序列\(A\),定义一段区间\([l,r]\)的分值为\(\left\{\begin{aligned}(r-l+1)&,s>0\\0&,s=0\\-(r-l+1)&,s<0\end{aligned}\right.\),其中\(s=\sum\limits_{i=l}^ra_i\),求划分成若干个子段后的最大分值和

    我们记\(F[i]\)表示\(1\sim i\)的最大分值,考虑转移:\(F[r]=F[l-1]+(r-(l-1))\),如果\(\sum\limits_{i=l}^ra_i>0\)。如何满足条件?我们将前缀和离散化,用树状数组维护即可。树状数组内存\(F[i]-i\),则每次更新即为\(F[x]=\mathrm{Query}()+x\)。具体见代码

    /*program from Wolfycz*/
    #include<map>
    #include<set>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define Fi first
    #define Se second
    #define lMax 1e18
    #define MK make_pair
    #define iMax 0x7f7f7f7f
    #define sqr(x) ((x)*(x))
    #define pii pair<int,int>
    #define lowbit(x) ((x)&(-x))
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    template<typename T>inline T read(T x) {
        int f = 1; char ch = getchar();
        for (; ch < '0' || ch>'9'; ch = getchar())	if (ch == '-')	f = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())	x = (x << 1) + (x << 3) + ch - '0';
        return x * f;
    }
    inline void print(int x) {
        if (x < 0)	putchar('-'), x = -x;
        if (x > 9)	print(x / 10);
        putchar(x % 10 + '0');
    }
    const int N = 5e5;
    int A[N + 10], F[N + 10], n;
    ll Pre[N + 10], list[N + 10];
    struct S1 {
        int Tree[N + 10];
        S1() {
            memset(Tree, 128, sizeof(Tree));
        }
        void insert(int x, int v) { for (; x <= n; x += lowbit(x)) Tree[x] = max(Tree[x], v); }
        int Query(int x) {
            int res = -iMax;
            for (; x; x -= lowbit(x))   res = max(res, Tree[x]);
            return res;
        }
    }TA;//Tree Array
    void clear() {
        for (int i = 1; i <= n; i++)
            F[i] = TA.Tree[i] = -iMax;
    }
    int main() {
        int T = read(0);
        memset(F, 128, sizeof(F));
        while (T--) {
            n = read(0);
            for (int i = 1; i <= n; i++) {
                Pre[i] = Pre[i - 1] + (A[i] = read(0));
                list[i] = Pre[i];
            }
            list[0] = Pre[0];
            sort(list, list + 1 + n);
            int m = unique(list, list + 1 + n) - list;
            for (int i = 0; i <= n; i++)  Pre[i] = lower_bound(list, list + m, Pre[i]) - list + 1;
            TA.insert(Pre[0], F[0] = 0);
            for (int i = 1; i <= n; i++) {
                F[i] = max(F[i - 1] + (A[i] < 0 ? -1 : 0), TA.Query(Pre[i] - 1) + i);
                TA.insert(Pre[i], F[i] - i);
            }
            printf("%d\n", F[n]);
            clear();
        }
        return 0;
    }
    

    E:在一个\(n\times m\)的棋盘上放置半皇后,半皇后可以攻击同行同列以及同一主对角线上的所有格子。问最少放置多少个半皇后,可以使所有的格子都至少被一个半皇后攻击到?

    构造题。因为半皇后只能攻击主对角线,因此我们考虑将多个半皇后沿反对角线放置。多次试验后可得,将半皇后分为两组,沿反对角线放置在左上和右下角是最优做法。

    具体而言,当\(n=3k-1\)时,我们在左上角放置\(k\)个半皇后,在右下角放置\(k-1\)个半皇后即可。对于其他两种情况,我们只随便找个角落,放置1~2个半皇后即可

    /*program from Wolfycz*/
    #include<map>
    #include<set>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define lMax 1e18
    #define MK make_pair
    #define iMax 0x7f7f7f7f
    #define sqr(x) ((x)*(x))
    #define pii pair<int,int>
    #define lowbit(x) ((x)&(-x))
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    template<typename T>inline T read(T x) {
        int f = 1; char ch = getchar();
        for (; ch < '0' || ch>'9'; ch = getchar())	if (ch == '-')	f = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())	x = (x << 1) + (x << 3) + ch - '0';
        return x * f;
    }
    inline void print(int x) {
        if (x < 0)	putchar('-'), x = -x;
        if (x > 9)	print(x / 10);
        putchar(x % 10 + '0');
    }
    struct node {
        int x, y;
        node(int _x = 0, int _y = 0) { x = _x, y = _y; }
        void print() {
            printf("%d %d\n", x, y);
        }
    };
    vector<node>Ans;
    int main() {
        int n = read(0);
        if (n % 3 == 1) {
            Ans.push_back(node(n, n));
            n--;
        }
        if (n) {
            if (n % 3 == 0) {
                Ans.push_back(node(n, n));
                n--;
            }
            int m = (n + 1) / 3;
            for (int i = 1; i <= m; i++)
                Ans.push_back(node(i, m - i + 1));
            for (int i = 1; i < m; i++)
                Ans.push_back(node(n - i + 1, n - m + 1 + i));
        }
        printf("%d\n", (int)Ans.size());
        for (auto p : Ans)
            p.print();
        return 0;
    }
    

    F:给定一棵树,若一条边的两端点入度和为偶数,则可将其删去。问是否存在一种删边的顺序,使得所有边都可以被删掉?

    对于一个点而言,若其度数为奇,则必定先删除与奇度数点相连的边,然后再为与偶度数点相连的边,依此类推,可知其删边必定是交替存在的。故一个点的所有出边内,要么偶度数与奇度数点相同,要么奇度数点比偶度数点多一。

    此外,考虑可以删边的情况,一条边的两个端点度数必定全为奇或者偶,我们记前者为奇边,后者为偶边。我们可以从叶子节点开始,依此确定每条边在删除的时候两端点的奇偶性,并且判断其是否合法。

    如果合法,则我们可以从根节点开始递归处理出一条可行的方案,具体可以见代码

    /*program from Wolfycz*/
    #include<map>
    #include<set>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define lMax 1e18
    #define MK make_pair
    #define iMax 0x7f7f7f7f
    #define sqr(x) ((x)*(x))
    #define pii pair<int,int>
    #define lowbit(x) ((x)&(-x))
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    template<typename T>inline T read(T x) {
        int f = 1; char ch = getchar();
        for (; ch < '0' || ch>'9'; ch = getchar())	if (ch == '-')	f = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())	x = (x << 1) + (x << 3) + ch - '0';
        return x * f;
    }
    inline void print(int x) {
        if (x < 0)	putchar('-'), x = -x;
        if (x > 9)	print(x / 10);
        putchar(x % 10 + '0');
    }
    const int N = 2e5;
    int pre[(N << 1) + 10], now[N + 10], child[(N << 1) + 10], tot;
    void link(int x, int y) { pre[++tot] = now[x], now[x] = tot, child[tot] = y; }
    void connect(int x, int y) { link(x, y), link(y, x); }
    int Parity[N + 10];
    bool Flag;
    void Dfs(int x, int fa) {
        int Cnt[2] = { 0, 0 };
        for (int p = now[x]; p; p = pre[p]) {
            int son = child[p];
            if (son == fa)    continue;
            Dfs(son, x);
            Cnt[Parity[son]]++;
        }
        if (x != 1) {
            Parity[x] = (Cnt[0] >= Cnt[1]);
            Cnt[Parity[x]]++;
        }
        Flag |= Cnt[1]<Cnt[0] || Cnt[1]>Cnt[0] + 1;
    }
    void solve(int x, int fa) {
        vector<int>Ans[2];
        int Cnt = 0;
        for (int p = now[x]; p; p = pre[p]) {
            int son = child[p];
            Ans[Parity[son == fa ? x : son]].push_back(son == fa ? x : son);
            Cnt++;
        }
        int ID = Cnt % 2;
        for (int i = 0; i < Cnt; i++) {
            int V = Ans[ID].back();
            if (V == x) {
                printf("%d %d\n", x, fa);
            }
            else   solve(V, x);
            Ans[ID].pop_back();
            ID ^= 1;
        }
    }
    void clear(int n) {
        tot = Flag = 0;
        for (int i = 1; i <= n; i++)  now[i] = Parity[i] = 0;
    }
    int main() {
        int T = read(0);
        while (T--) {
            int n = read(0);
            for (int i = 1; i < n; i++) {
                int x = read(0), y = read(0);
                connect(x, y);
            }
            Dfs(1, 0);
            if (Flag) {
                printf("NO\n");
                goto CLEAR;
            }
            printf("YES\n");
            solve(1, 0);
            
        CLEAR:
            clear(n);
        }
        return 0;
    }
    
  • 相关阅读:
    中专毕业后我的七年(励志篇,年轻人必看)
    Excel实战技巧之[二级条件级联]
    kingston DataTraveler2.0 4GU盘量产成功
    Windows XP SP3增强补丁 V1.3 破解uxtheme.dll和TCP/IP连接数的破解
    诺基亚系列手机型号命名研究
    硬件检测相关工具大全
    最好的MacOSX美化包——MacXize(支持SP3)
    我终于把《新概念英语》三册&四册全背下来了
    IBM T22故障
    Windows通用克隆系统入门基础知识简介
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/16295428.html
Copyright © 2020-2023  润新知