CodeForces 878 简要题解

A. Short Program

起床困难综合征,随便构造一下就好了。

#include 
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

inline int Read()
{
    int x = 0, f = 1, c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            f = -1;
    for (;  isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

int n, x, y = 1023;
char opt[3];

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1, z; i <= n; i ++)
    {
        scanf("%s", opt), z = Read();
        if (opt[0] == '&')
            x &= z, y &= z;
        else if (opt[0] == '|')
            x |= z, y |= z;
        else
            x ^= z, y ^= z;
    }
    puts("2");
    printf("& %d\n", x ^ y);
    printf("^ %d\n", x);
    return 0;
}

B. Teams Formation

先用栈把内部的消掉,剩下的一定是消一头一尾。

消的时候如果一头一尾的出现次数加起来恰好为 k 就消下去,注意一些边界情况。

#include 
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

inline int Read()
{
    int x = 0, f = 1, c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            f = -1;
    for (;  isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

const int MAXN = 100005;

int n, m, q, c, a[MAXN], b[MAXN];
LL ans;

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read(), q = Read();
    for (int i = 1, x; i <= n; i ++)
        if ((x = Read()) == a[c])
        {
            b[c] ++;
            if (b[c] == m)
                c --;
        }
        else
            c ++, a[c] = x, b[c] = 1;
    if (!c)
        return puts("0"), 0;
    int tot = 0, del = 0, pos = 0;
    for (int i = 1; i <= c; i ++)
        tot += b[i];
    for (int i = 1; i < c + 1 - i; i ++)
        if (a[i] == a[c + 1 - i] && b[i] + b[c + 1 - i] == m)
            del += m;
        else
        {
            pos = i;
            break;
        }
    if (pos)
    {
        if (a[pos] == a[c + 1 - pos] && b[pos] + b[c + 1 - pos] > m)
            del += m;
        ans = 1LL * tot * q - 1LL * del * (q - 1);
    }
    else
    {
        ans = 1LL * b[(c >> 1) + 1] * q % m;
        if (ans)
            ans += tot - b[(c >> 1) + 1];
    }
    cout << ans << endl;
    return 0;
}

C. Tournament

题目名字提示类似竞赛图。

首先变成图论问题, i 能赢 j 连边 (i,j) ,可以赢的人一定能到达所有点。

两个点之间至少有一条边,就是说缩环之后是一条链。

新加一个点可能带来缩掉若干个SCC,对于每个SCC维护每种属性的最大最小值,用set维护一下链上的相对位置关系,暴力缩环即可。

#include 
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

inline int Read()
{
    int x = 0, f = 1, c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            f = -1;
    for (;  isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

const int MAXN = 50005;

int n, m, siz[MAXN], l[MAXN][10], r[MAXN][10];
set  s;

inline bool Win(int x, int y)
{
    for (int i = 0; i < m; i ++)
        if (r[x][i] > l[y][i])
            return true;
    return false;
}

inline void Insert(int x)
{
    siz[x] = 1;
    while (true)
    {
        auto it = s.lower_bound(mp(l[x][0], x));
        if (it != s.end() && Win(x, it -> yy))
        {
            for (int i = 0; i < m; i ++)
                l[x][i] = min(l[x][i], l[it -> yy][i]), r[x][i] = max(r[x][i], r[it -> yy][i]);
            siz[x] += siz[it -> yy];
            s.erase(it);
        }
        else
            break;
    }
    while (true)
    {
        auto it = s.lower_bound(mp(l[x][0], x));
        if (it != s.begin())
        {
            it --;
            if (Win(it -> yy, x))
            {
                for (int i = 0; i < m; i ++)
                    l[x][i] = min(l[x][i], l[it -> yy][i]), r[x][i] = max(r[x][i], r[it -> yy][i]);
                siz[x] += siz[it -> yy];
                s.erase(it);
            }
            else
                break;
        }
        else
            break;
    }
    s.insert(mp(l[x][0], x));
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read();
    for (int i = 1; i <= n; i ++)
        for (int j = 0; j < m; j ++)
            l[i][j] = r[i][j] = Read();
    for (int i = 1; i <= n; i ++)
        Insert(i), printf("%d\n", siz[(-- s.end()) -> yy]);
    return 0;
}

D. Magic Breeding

考虑将 ai 变成 0/1 ,那么取 max min 相当于 or and 操作。

每个序列可以用一个 2k 位二进制数表示,第 S 位表示初始的 0/1 状态为 S ,那么这个序列的状态是什么,用bitset加速即可。

#include 
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

inline int Read()
{
    int x = 0, f = 1, c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            f = -1;
    for (;  isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

const int MAXN = 100005;
const int MAXM = 4100;

int n, m, q, c, a[12][MAXN];
bitset  b[MAXN];

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    m = Read(), n = c = Read(), q = Read();
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < m; j ++)
            a[i][j] = Read();
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < 1 << n; j ++)
            if (j >> i & 1)
                b[i][j] = 1;
    for (int i = 1, opt, x, y; i <= q; i ++)
        if ((opt = Read()) == 1)
            x = Read() - 1, y = Read() - 1, b[n ++] = b[x] | b[y];
        else if (opt == 2)
            x = Read() - 1, y = Read() - 1, b[n ++] = b[x] & b[y];
        else
        {
            x = Read() - 1, y = Read() - 1;
            int ans = 0;
            for (int j = 0; j < c; j ++)
            {
                int cur = 0;
                for (int k = 0; k < c; k ++)
                    if (a[k][y] >= a[j][y])
                        cur |= 1 << k;
                if (b[x][cur])
                    ans = max(ans, a[j][y]);
            }
            printf("%d\n", ans);
        }
    return 0;
}

E. Numbers on the blackboard

首先单次询问可以倒着贪心做,如果是负数就把它乘二加到答案(最后合并),否则去和前一个合并。

求出 i 往前这样做一步的长度,倍增加速询问。

注意代码里虽然写了 2 层for,但是均摊下来应该是 nlogn 的。

#include 
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

inline int Read()
{
    int x = 0, f = 1, c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            f = -1;
    for (;  isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

const int MAXN = 100005;
const int mod = 1e9 + 7;

int n, m, a[MAXN], bin[MAXN], inv[MAXN], s[MAXN], f[18][MAXN], g[18][MAXN];

inline int Get(int l, int r)
{
    return 1LL * (s[r] - s[l - 1] + mod) * inv[l - 1] % mod;
}

inline int Solve(int l, int r)
{
    int ret = 0;
    for (int i = 17; ~i; i --)
        if (f[i][r] >= l)
            ret = (ret + g[i][r]) % mod, r = f[i][r];
    ret = (ret + Get(l, r)) % mod;
    return ret;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read(), bin[0] = inv[0] = 1;
    for (int i = 1; i <= n; i ++)
        a[i] = Read(), bin[i] = (bin[i - 1] << 1) % mod, inv[i] = 1LL * inv[i - 1] * (mod + 1 >> 1) % mod, s[i] = (1LL * bin[i] * (a[i] + mod) + s[i - 1]) % mod;
    for (int i = 1; i <= n; i ++)
    {
        LL cur = 0;
        for (int j = i; j; j --)
        {
            cur = 2 * (cur + a[j]);
            if (cur <= 0)
            {
                f[0][i] = j - 1, g[0][i] = (cur % mod + mod) % mod;
                break;
            }
            else if (cur > 2000000000)
            {
                f[0][i] = -1;
                break;
            }
        }
    }
    for (int i = 1; i < 18; i ++)
        for (int j = 1; j <= n; j ++)
            if (!~f[i - 1][j])
                f[i][j] = -1;
            else
                f[i][j] = f[i - 1][f[i - 1][j]], g[i][j] = (g[i - 1][j] + g[i - 1][f[i - 1][j]]) % mod;
    while (m --)
    {
        int l = Read(), r = Read(), ret = (a[l] + Solve(l + 1, r)) % mod;
        printf("%d\n", (ret + mod) % mod);
    }
    return 0;
}

质量挺高的…感觉姿势不对这场每个题(除了A)细节都会比较鬼畜…

你可能感兴趣的:(CodeForces 878 简要题解)