• [CodeForces]Codeforces Round #433


    854A. Fraction

    题意

    给定$n$,求分子分母和为$n$且分母最大的最简分数。

    题解

    暴力枚举。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    inline int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
    int main() {
        int n; scanf("%d", &n);
        for (int a = n / 2; a >= 1; a--) {
            int b = n - a;
            if (gcd(a, b) == 1) return 0 * printf("%d %d
    ", a, b);
        }
        return 0;
    }
    

    854B. Maxim Buys an Apartment

    题意

    给定$n$和$k$,表示$n$个连续位置中已经放了$k$个点。现在继续在剩余位置放点,必须与$k$个点中至少一个相邻。求能放的点的数量最小值和最大值。

    题解

    最小值,除非$k=0$或$k=n$时为$0$,其他情况都为$1$。
    最大值,考虑将$k$个点相隔两个放置一定最优,也就是一个点能管包括本身在内的三个点,画个图就明白了。

    代码

    #include <bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    int main() {
        ll n, k; scanf("%lld%lld", &n, &k);
        if (k == n || k == 0) return 0 * puts("0 0");
        return 0 * printf("1 %lld
    ", k * 3 >= n ? n - k : k * 2);
    }
    

    853A. Planning

    题意

    给定$n$架飞机$1-n$,本来第$i$架对应在第$i$分钟起飞。由于延误,起飞时间区间改为$[k+1,k+n]$。第$i$架飞机延迟一分钟损失$c_i$。调整起飞时间,要求不能同时起飞,不能比原来早。求最小损失。

    题解

    贪心:对于$[k+1,k+n]$内的每个时刻,我们尽可能让能起飞且损失最大的飞机起飞。
    下面我们简单证明一下:
    设每架飞机新的起飞时间为$t_i$,则总损失为$sum_{i=1}^{n}c_i imes (t_i-i)=sum_{i=1}^{n}c_i imes t_i-sum_{i=1}^{n}c_i imes i$。
    我们注意到$sum_{i=1}^{n}c_i imes i$是个常数,要求总损失最小,即让$sum_{i=1}^{n}c_i imes t_i$最小。联想排序不等式,容易证明贪心的正确性。
    在贪心过程中,我们需要维护当前时间能起飞飞机的损失最大值,使用$Heap$、$STL$中的$set$或$priority\_queue$即可。
    时间复杂度:$Theta(n imes logn)$。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pir;
    const int N = 3e5+9;
    int c[N], res[N];
    priority_queue<pir> pq;
    inline int read() {
        int s = 1, a = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
        return s * a;
    }
    int main() {
        int n = read(), k = read();
        for (int i = 1; i <= n; i++) c[i] = read();
        for (int i = 1; i <= k; i++) pq.push(make_pair(c[i], i));
        ll cost = 0;
        for (int i = k + 1; i <= k + n; i++) {
            if (i <= n) pq.push(make_pair(c[i], i));
            int t = pq.top().second;
            pq.pop();
            res[t] = i;
            cost += 1ll * (i - t) * c[t];
        }
        printf("%lld
    ", cost);
        for (int i = 1; i < n ; ++i) printf("%d ", res[i]);
        return 0 * printf("%d
    ", res[n]);;
    }
    

    853B. Jury Meeting

    题意

    给定$n$个城市的人要去城市$0$开会,有$m$架从城市$0$出发或者到达城市$0$的飞机,要求每个城市的人来了还要回去且$n$个城市的人呆在一起的时间大于等于$k$天。求最小花费。

    题解

    首先,每个城市的人都需要一架去、一架回的飞机,那么在时间轴上,即要选$n$个线段使它们重合部分长度$geq k$。
    然后,我们考虑若第$i$天所有城市的人都在城市$0$,第$i$天之前要有$n$架不同飞机到达城市$0$,之后也要有$n$架不同飞机离开城市$0$。对于第$i$天,预处理前缀和$pre_i,suf_i$,分别表示第$i$天前、后,$n$架不同城市的飞机到达、离开城市$0$所需要的最少花费。
    最后,按天数扫一遍,取$min_{1leq ileq d_{max}}pre_i+suf_{i+k+1}$即可。
    时间复杂度:$Theta(m imes logm+n)$。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pir;
    const int N = 1e5+9;
    const int D = 1e6+9;
    const ll INF = 1e12;
    vector<pir> fr[N], to[N];
    ll pre[D], suf[D];
    inline int read() {
        int s = 1, a = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
        return s * a;
    }
    int main() {
        int n = read(), m = read(), k = read();
        for (int i = 1; i <= m; i++) {
            int d = read(), f = read(), t = read(), c = read();
            if (f) fr[f].push_back(make_pair(d, c));
            if (t) to[t].push_back(make_pair(d, c));
        }
        for (int i = 1; i <= n; i++)     {
            sort(fr[i].begin(), fr[i].end(), less<pir>());
            ll l1 = INF; pre[0] += l1;
            for (auto p : fr[i]) {
                pre[p.first] += min(0ll, p.second - l1);
                l1 += min(0ll, p.second - l1);
            }
            sort(to[i].begin(), to[i].end(), greater<pir>());
            ll l2 = INF; suf[D - 1] += l2;
            for (auto p : to[i]) {
                suf[p.first] += min(0ll, p.second - l2);
                l2 += min(0ll, p.second - l2);
            }
        }
        for (int j = 1; j < D; j++) pre[j] += pre[j - 1];
        for (int j = D - 2; j; j--) suf[j] += suf[j + 1];
        ll res = n * INF;
        for (int j = 0; j < D - k - 1; j++) res = min(res, pre[j] + suf[j + k + 1]);
        return 0 * (res >= INF ? puts("-1
    ") : printf("%lld
    ", res));
    }
    

    853C. Boredom

    题意

    给定一个$n imes n$的点阵,每列有一个标记点;定义“美丽矩形”为任意两个标记点构成的矩形,显然一共有$frac{n imes(n-1)}{2}$个。有$q$个询问,每次询问一个矩形与多少个“美丽矩形”相交。

    题解

    我们考虑每个询问的矩形,将它的四条边延长下去,会将原来的点阵最多划分成$9$个矩形,统计每个小矩形中标记点的数量,简单容斥一下就能得到答案。
    下面主要任务是预处理出前$i$列$[l,r]$行中标记点的数量,这个用可持久化线段树即可。
    时间复杂度:$Theta(n imes logn+8q imes logn)$。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+9;
    int tot, root[N];
    struct Tree {
        int l, r, sum;
    } tree[N * 40];
    inline int read() {
        int s = 1, a = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
        return s * a;
    }
    inline ll f(int x) {
        return 1ll * x * (x - 1) / 2;
    }
    inline void update(int m, int l, int r, int t, int tt) {
        tree[t].sum++;
        if (l == r) return;
        else {
            int mid = (l + r) >> 1;
            if (m <= mid) {
                tree[t].l = ++tot;
                tree[ tree[t].l ] = tree[ tree[tt].l ];
                update(m, l, mid, tree[t].l, tree[tt].l);
            }
            else {
                tree[t].r = ++tot;
                tree[ tree[t].r ] = tree[ tree[tt].r ];
                update(m, mid+1, r, tree[t].r, tree[tt].r);
            }
        }
    }
    inline int query(int ql, int qr, int l, int r, int t, int tt) {
        if (ql > qr) return 0;
        if (ql <= l && r <= qr) return tree[t].sum - tree[tt].sum;
        else {
            int ret = 0, mid = (l + r) >> 1;
            if (ql <= mid) ret += query(ql, qr, l, mid, tree[t].l, tree[tt].l);
            if (qr > mid) ret += query(ql, qr, mid+1, r, tree[t].r, tree[tt].r);
            return ret;
        }
    }
    int main() {
        int n = read(), q = read();
        for (int i = 1; i <= n; i++) {
            int p = read();
            root[i] = ++tot;
            tree[ root[i] ] = tree[ root[i - 1] ];
            update(p, 1, n, root[i], root[i - 1]);
        }
        for (int i = 1; i <= q; i++) {
            int l = read(), d = read(), r = read(), u = read();
            ll res = f(n);
            res -= f( query(1, d-1, 1, n, root[n], root[0]) );
            res -= f( query(u+1, n, 1, n, root[n], root[0]) );
            res -= f( query(1, n, 1, n, root[l-1], root[0]) );
            res -= f( query(1, n, 1, n, root[n], root[r]) );
            res += f( query(1, d-1, 1, n, root[l-1], root[0]));
            res += f( query(1, d-1, 1, n, root[n], root[r]));
            res += f( query(u+1, n, 1, n, root[n], root[r]));
            res += f( query(u+1, n, 1, n, root[l-1], root[0]));
            printf("%lld
    ", res);
        }
        return 0;
    }
    

    853D. Michael and Charging Stations

    题意

    给定$n$个商品价格为$a_i=1000$或$a_i=2000$。每件商品若付全款,则将返回$10\%$的钱来抵现金。求最小花费。

    题解

    吾本以为$Div1.D$必有高论。。。
    裸$DP$。
    首先,我们用$dp[i][j]$表示前$i$天可以抵现金的钱为$j$的最小花费。
    然后,我们把价格都除以$100$,发现当前状态能抵现金的钱不可能超过$30$,否则显然可以用来买下一个商品,那么$jleq 30$。
    最后,$dp$方程就很显然了:
    $egin{equation}
    dp[i][j]=min
    egin{cases}
    dp[i-1][j-frac{a_i}{10}]+a_i&,付全款 ewline
    dp[i-1][j+max(0,a_i-j)]+max(0,a_i-j)&,抵现金 ewline
    end{cases}
    end{equation}$
    时间复杂度:$Theta(30 imes n)$。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 3e5+9;
    const int INF = 1e9+7;
    int a[N], dp[2][31];
    inline int read() {
        int s = 1, a = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
        return s * a;
    }
    int main() {
        int n = read();
        for (int i = 1; i <= n; i++) a[i] = read() / 100;
        for (int i = 1; i <= 30; i++) dp[0][i] = INF;
        for (int i = 1, b = 1; i <= n; i++, b ^= 1) {
            for (int j = 0; j <= 30; j++) dp[b][j] = INF;
            for (int j = 0; j <= 30; j++) {
                dp[b][ j + a[i] / 10 ] = min(dp[b][ j + a[i] / 10 ], dp[b ^ 1][j] + a[i]);
                dp[b][ j - a[i] + max(a[i] - j, 0) ] = min(dp[b][ j - a[i] + max(a[i] - j, 0) ], dp[b ^ 1][j] + max(a[i] - j, 0));
            }
        }
        int res = INF;
        for (int i = 0; i <= 30; i++) res = min(res, dp[n % 2][i]);
        return 0 * printf("%d00
    ", res);
    }
    
  • 相关阅读:
    document.URL 和 windows.location.href的区别
    毕向东udp学习笔记3多线程聊天
    毕向东udp学习笔记2
    毕向东udp学习笔记1
    udp 服务器界面监听
    android jni 总复习(转载)
    Android jni 编程4(对基本类型二维整型数组的操作)
    Android jni 编程3(对基本类型一维整型数组的操作)总结版
    Android jni 编程2(对基本类型一维整型数组的操作)
    Android jni 编程1(对基本类型字符串的操作)
  • 原文地址:https://www.cnblogs.com/jstztzy/p/7491551.html
Copyright © 2020-2023  润新知