比赛链接:传送门


Codeforces1249A. Yet Another Dividing into Teams(水题)

代码:

#include <bits/stdc++.h>
#define N 105

using namespace std;

int a[N];
int main()
{
    int q;
    cin >> q;
    while (q--) {
        int n; cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        sort(a+1, a+1+n);
        int ans = 1;
        for (int i = 2; i <= n; i++) {
            if (a[i] == a[i-1] + 1) {
                ans++;
                break;
            }
        }
        cout << ans << endl;
    }
    return 0;
}
View Code

Codeforces1249B2. Books Exchange (hard version)

一本书在一个周期内经过的路径中的每个人,拿到自己原来的书所需要的时间都等于这个周期的长度。

代码:O(n)

#include <bits/stdc++.h>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 200005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
    int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
    do{++len; c[len] = x%10 + '0';} while (x /= 10);
    for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }

ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a%b);
}

int p[N], ans[N];
int solve(int x) {
    int len = 0;
    int tmp = x;
    do {
        tmp = p[tmp];
        len++;
    } while (tmp != x);
    do {
        ans[tmp] = len;
        tmp = p[tmp];
    } while (tmp != x);
    return len;
}
int main()
{
    int q;
    cin >> q;
    while (q--) {
        int n; read(n);
        for (int i = 1; i <= n; i++) {
            ans[i] = 0;
        }
        for (int i = 1; i <= n; i++)
            read(p[i]);
        for (int i = 1; i <= n; i++) {
            if (!ans[i]) {
                solve(i);
            }
        }
        for (int i = 1; i <= n; i++) {
            printf("%d%c", ans[i], " \n"[i==n]);
        }
    }
    return 0;
}
View Code

Codeforces1249C2. Good Numbers (hard version)(进制转换 贪心)

把n转化成三进制放在数组中,如果有2的话说明要找比n大的最小的满足条件的。

只要把权值最大的2加一变成3,然后进位。并把比这个2小的所有三进制数值置零就行了。

比如129用三进制表示是1121。操作过程中的值就是:1121->1200->2000->10000。结果就是3 = 243。

代码:O(logn)

#include <bits/stdc++.h>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 200005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
    int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
    do{++len; c[len] = x%10 + '0';} while (x /= 10);
    for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }

ll b[N], a[N];
int main()
{
    b[0] = 1;
    for (int i = 1; i <= 38; i++) {
        b[i] = b[i-1] * 3;
    }
    int q; read(q);
    while (q--) {
        ll n; read(n);
        for (int i = 38; i >= 0; i--) {
            a[i] = n/b[i];
            n %= b[i];
        }
        int st = 0;
        for (int i = 38; i >= 0; i--) {
            if (a[i] == 2) {
                st = i;
                break;
            }
        }
        for (int i = 0; i < st; i++) {
            a[i] = 0;
        }
        for (int i = st; i <= 38; i++) {
            if (a[i] >= 2) {
                a[i] = 0;
                a[i+1]++;
            }
        }
        ll ans = 0;
        for (int i = 0; i <= 38; i++) {
            if (a[i])
                ans += b[i];
        }
        cout << ans << endl;
    }
    return 0;
}
View Code

Codeforces1249D2. Too Many Segments (hard version)(扫描线+单调队列+multiset维护)

这题好像比E难的样子。

思路:

考虑从左到右枚举每一个小区间,看这个小区间被多少个线段覆盖。如果被超过k个线段覆盖,则把这些线段中右端点最大的一个remove掉。

实现:

先把所有线段按l、r从小到大排序,然后从左到右遍历。

对于每一条线段(l0,r0),考虑维护之前有多少个线段的r比l0大。具体的就是保存之前的所有的r,如果r < l0,则把这些r删去。(这里可以用单调队列或者set维护,但是考虑后面的操作,这里选择了set)

如果比l0大的r的数量超过了k,那么就贪心地删去里面最大的那个r(这里就体现了set的方便之处,可以直接erase(--set.end()))。考虑到会有重复元素,所以set要换成multiset。

代码:O(nlogk)

#include <bits/stdc++.h>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 200005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
    int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
    do{++len; c[len] = x%10 + '0';} while (x /= 10);
    for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }

struct Node{
    int l, r, id;
    bool operator < (const Node& x) const {
        if (l == x.l)
            return r < x.r;
        return l < x.l;
    }
}nodes[N];

struct SNode{
    int val, id;
    bool operator < (const SNode& x) const {
        return val < x.val;
    }
};

multiset <SNode> S;
vector <int> ans;
int main()
{
    int n, k; read(n, k);
    for (int i = 1; i <= n; i++) {
        read(nodes[i].l, nodes[i].r);
        nodes[i].id = i;
    }
    sort(nodes+1, nodes+1+n);
    for (int i = 1; i <= n; i++) {
        while (!S.empty() && (*S.begin()).val < nodes[i].l)
            S.erase(S.begin());
        S.insert(SNode{nodes[i].r, nodes[i].id});
        if (sz(S) > k) {
            ans.push_back((*--S.end()).id);
            S.erase(--S.end());
        }
    }
    sort(ans.begin(), ans.end());
    cout << ans.size() << endl;
    for (int i = 0; i < sz(ans); i++) {
        printf("%d%c", ans[i], " \n"[i == sz(ans)-1]);
    }
    return 0;
}
View Code

Codeforces1249E. By Elevator or Stairs?(dp)

思路:

上楼肯定是要一层一层上的,所以每层楼只要考虑下面那层楼爬到这一层楼的情况。

设当前楼层为i,$f_{i,0/1}$表示到达第i层楼时,最后一层是走楼梯(0)或者电梯(1)所需要的最短时间。

显然有$f_{1,0} = 0$,特别地,令$f_{1,1}=c$。

1、如果我上第i层楼想走楼梯,那么:$f_{i,0} = min(f_{i-1,0}+a_{i-1}, f_{i-1, 1}+a_{i-1})$

2、如果我上第i-1层楼走的楼梯,并且第i层楼想走电梯的话,要花c的时间等电梯:$f_{i,1} = min(f_{i,1}, f_{i-1,0}+c+b_{i-1})$

3、如果我上第i-1层楼走的电梯,并且第i层楼想走电梯的话,不用再花时间等电梯了:$f_{i,1} = min(f_{i,1}, f_{i-1,1}+b_{i-1})$

显然到达第i层楼的最短时间是$min(f_{i,0}, f_{i,1})$

代码:O(n)

#include <bits/stdc++.h>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 200005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
    int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
    do{++len; c[len] = x%10 + '0';} while (x /= 10);
    for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }

int a[N], b[N];
int f[N][2];// 0 stair 1 elevator
int main()
{
    int n, c; read(n, c);
    for (int i = 1; i < n; i++)
        read(a[i]);
    for (int i = 1; i < n; i++)
        read(b[i]);
    memset(f, 0x3f, sizeof f);
    f[1][0] = 0;
    f[1][1] = c;
    for (int i = 2; i <= n; i++) {
        f[i][0] = min(f[i][0], f[i-1][0] + a[i-1]);
        f[i][0] = min(f[i][0], f[i-1][1] + a[i-1]);
        f[i][1] = min(f[i][1], f[i-1][0] + c + b[i-1]);
        f[i][1] = min(f[i][1], f[i-1][1] + b[i-1]);
    }
    for (int i = 1; i <= n; i++) {
        printf("%d%c", min(f[i][0], f[i][1]), " \n"[i==n]);
    }
    return 0;
}
View Code

 

01-02 00:54