CodeChef AUG17 简要题解

RAINBOWA

签到。

#include <bits/stdc++.h>
#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 = 105;

int n, a[MAXN];

inline bool Solve(int l, int r, int t)
{
    if (t == 7)
    {
        for (int i = l; i <= r; i ++)
            if (a[i] ^ 7)
                return false;
        return true;
    }
    if (a[l] != t || a[r] != t)
        return false;
    while (l <= r && a[l] == t && a[r] == t)
        l ++, r --;
    if (l > r)
        return false;
    return Solve(l, r, t + 1);
}

inline void Sol()
{
    n = Read();
    for (int i = 1; i <= n; i ++)
        a[i] = Read();
    puts(Solve(1, n, 1) ? "yes" : "no");
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Sol();
    return 0;
}

CHEFMOVR

签到。

#include <bits/stdc++.h>
#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 = 200005;

int n, m;
LL a[MAXN];

inline void Sol()
{
    n = Read(), m = Read();
    for (int i = 1; i <= n; i ++)
        a[i] = Read();
    LL ave = 0, ans = 0;
    for (int i = 1; i <= m; i ++)
    {
        LL tot = 0, cnt = 0;
        for (int j = i; j <= n; j += m)
            tot += a[j], cnt ++;
        if (tot % cnt)
        {
            puts("-1");
            return ;
        }
        tot /= cnt;
        if (i == 1)
            ave = tot;
        else if (ave ^ tot)
        {
            puts("-1");
            return ;
        }
    }
    for (int i = 1; i <= n; i ++)
        a[i] -= ave;
    for (int i = 1; i <= n; i ++)
        ans += abs(a[i]), a[i + m] += a[i];
    printf("%lld\n", ans);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Sol();
    return 0;
}

GCAC

签到。

#include <bits/stdc++.h>
#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 = 1005;

int n, m, a[MAXN], b[MAXN], c[MAXN], h[MAXN];
char s[MAXN];

inline void Sol()
{
    LL d = 0, e = 0, f = 0;
    n = Read(), m = Read();
    for (int i = 1; i <= n; i ++)
        a[i] = Read();
    for (int i = 1; i <= m; i ++)
        b[i] = Read(), c[i] = Read(), h[i] = 0;
    for (int i = 1; i <= n; i ++)
    {
        scanf("%s", s + 1);
        int g = 0;
        for (int j = 1; j <= m; j ++)
            if (s[j] == '1' && c[j] && b[j] >= a[i] && b[j] > b[g])
                g = j;
        if (g)
            d ++, e += b[g], c[g] --, h[g] = 1;
    }
    for (int i = 1; i <= m; i ++)
        f += !h[i];
    printf("%lld %lld %lld\n", d, e, f);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Sol();
    return 0;
}

PALINGAM

分类讨论一下。
如果A的字符集是B的子集,那么A出什么B都能拼出来,B赢。
否则如果B是A的子集,A可以先出一个B没有的,然后B随便出什么A都可以拼这个,A赢。
然后如果存在相交的,如果A有某个B没有的字符出现了 2 次,那么A赢。
其他情况,B一定可以拖到结束,B赢。

#include <bits/stdc++.h>
#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 = 505;

int n, a[26], b[26];
char s[MAXN], t[MAXN];

inline void Sol()
{
    scanf("%s%s", s + 1, t + 1); n = strlen(s + 1);
    for (int i = 0; i < 26; i ++)
        a[i] = b[i] = 0;
    for (int i = 1; i <= n; i ++)
        a[s[i] - 'a'] ++, b[t[i] - 'a'] ++;
    bool flag = true;
    for (int i = 0; i < 26; i ++)
        if (a[i] && !b[i])
            flag = false;
    if (flag)
    {
        puts("B");
        return ;
    }
    flag = true;
    for (int i = 0; i < 26; i ++)
        if (b[i] && !a[i])
            flag = false;
    if (flag)
    {
        puts("A");
        return ;
    }
    for (int i = 0; i < 26; i ++)
        if (a[i] > 1 && !b[i])
            flag = true;
    if (flag)
        puts("A");
    else
        puts("B");
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Sol();
    return 0;
}

CHEFFA

假设fi表示进行了多少次 ai1,ai+11,ai+2+1 ,那么显然 fi+fi1ai+fi2 ,范围很小,随便DP一下就好了。

#include <bits/stdc++.h>
#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 = 505;
const int mod = 1e9 + 7;

int n, m, a[MAXN], f[MAXN][MAXN][MAXN];

inline void Sol()
{
    mset(f, 0);
    n = Read(), m = max(n + 50, n << 1);
    for (int i = 1; i <= n; i ++)
        a[i] = Read();
    for (int i = n + 1; i <= m; i ++)
        a[i] = 0;
    f[0][0][0] = 1;
    for (int i = 0; i < m; i ++)
        for (int j = 0; j <= 500; j ++)
            for (int k = 0; k <= 500; k ++)
                if (f[i][j][k])
                    for (int l = 0; l <= a[i + 1] + k - j; l ++)
                        f[i + 1][l][j] = (f[i + 1][l][j] + f[i][j][k]) % mod;
    int ret = 0;
    for (int i = 0; i <= 500; i ++)
        for (int j = 0; j <= 500; j ++)
            ret = (ret + f[m][i][j]) % mod;
    printf("%d\n", ret);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Sol();
    return 0;
}

STRINGRA

这个条件本质上就是 prei i1 之间的向 i 连一条有向边。
这个结论很显然,就不证了。

#include <bits/stdc++.h>
#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, a[MAXN];
vector <int> adj[MAXN];

inline void Sol()
{
    int cnt = 0;
    n = Read(), m = Read();
    for (int i = 0; i <= n; i ++)
        adj[i].clear();
    for (int i = 1, x, y; i <= m; i ++)
        x = Read(), y = Read(), adj[y].pb(x);
    if (adj[0].size())
    {
        puts("-1");
        return ;
    }
    for (int i = 1; i <= n; i ++)
    {
        sort(adj[i].begin(), adj[i].end());
        if (!adj[i].size())
        {
            puts("-1");
            return ;
        }
        for (int j = 1; j < adj[i].size(); j ++)
            if (adj[i][j] - adj[i][j - 1] ^ 1)
            {
                puts("-1");
                return ;
            }
        if (i - adj[i][adj[i].size() - 1] ^ 1)
        {
            puts("-1");
            return ;
        }
        if (!adj[i][0])
            a[i] = ++ cnt;
        else
        {
            a[i] = a[adj[i][0]];
            for (int j = adj[i][0] + 1; j < i; j ++)
                if (a[i] == a[j])
                {
                    puts("-1");
                    return ;
                }
        }
    }
    for (int i = 1; i <= n; i ++)
        printf("%d%c", a[i], i == n ? '\n' : ' ');
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Sol();
    return 0;
}

HILLJUMP

如果我们知道了nexti,那么我们可以用弹飞绵羊的办法随便分个块。
nexti 我们也可以分块,注意到 100 这个条件,我们可以暴力单调栈求出块,同时块大小大于 100 ,所以一次修改最多影响四个块。
每次暴力修改用个单调栈求 nexti

#include <bits/stdc++.h>
#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 = 325;
const int blk = 320;

int n, m, Q, bel[MAXN], nxt[MAXN], br[MAXN], bc[MAXN], st[425], tp;
LL a[MAXN], tag[MAXM];

inline void Rebuild(int id)
{
    if (id < 0 || id > m)
        return ;
    int l = id * blk + 1, r = min((id + 1) * blk, n);
    for (int i = l; i <= r; i ++)
    {
        while (tp && a[st[tp]] + tag[id] < a[i] + tag[id])
            nxt[st[tp --]] = i;
        st[++ tp] = i;
    }
    for (int i = r + 1; i <= min(n, r + 100); i ++)
        while (tp && a[st[tp]] + tag[id] < a[i] + tag[id + 1])
            nxt[st[tp --]] = i;
    while (tp)
        nxt[st[tp --]] = n + 101;
    for (int i = l; i <= r; i ++)
        if (nxt[i] - i > 100)
            nxt[i] = i;
    for (int i = r; i >= l; i --)
        if (nxt[i] > r || nxt[i] == i)
            br[i] = i, bc[i] = 0;
        else
            br[i] = br[nxt[i]], bc[i] = bc[nxt[i]] + 1;
}

inline int Query()
{
    int x = Read(), k = Read();
    while (true)
    {
        if (nxt[x] == x)
            return x;
        k --, x = nxt[x];
        if (!k)
            return x;
        if (k <= bc[x])
        {
            while (k --)
                x = nxt[x];
            return x;
        }
        k -= bc[x], x = br[x];
    }
}

inline void Modify()
{
    int l = Read(), r = Read(), k = Read(), bl = bel[l], br = bel[r];
    if (bl == br)
    {
        for (int i = l; i <= r; i ++)
            a[i] += k;
        Rebuild(bl);
        Rebuild(bl - 1);
        return ;
    }
    for (int i = l; i <= (bl + 1) * blk; i ++)
        a[i] += k;
    for (int i = br * blk + 1; i <= r; i ++)
        a[i] += k;
    for (int i = bl + 1; i < br; i ++)
        tag[i] += k;
    Rebuild(bl); Rebuild(bl - 1); Rebuild(br); Rebuild(br - 1);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(); Q = Read();
    for (int i = 1; i <= n; i ++)
        bel[i] = (i - 1) / blk, a[i] = Read();
    m = bel[n];
    for (int i = 0; i <= m; i ++)
        Rebuild(i);
    while (Q --)
        if (Read() == 1)
            printf("%d\n", Query());
        else
            Modify();
}

WALKBT

注意到答案本质上是树链的并。
那么我们需要一个 set ,然后用总长度减去相邻两个元素的 lcp 就是答案。
这启示我们用主席树维护哈希值来查询 lcp 和比较大小。
每个 1 最多贡献一次进位,暴力处理就好了。

#include <bits/stdc++.h>
#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 = 8000005;
const int bas1 = 233;
const int bas2 = 2333;
const int mod1 = 1e9 + 7;
const int mod2 = 1e9 + 9;

struct Node { int l, r; pii h; } e[MAXM]; 
int n, Q, tot, rt[MAXN], pw1[MAXN], pw2[MAXN], cnt;
LL ans;

inline void Build(int &x, int l, int r)
{
    e[x = ++ tot].h = mp(0, 0);
    if (l == r)
        return ;
    int mid = l + r >> 1;
    Build(e[x].l, l, mid); Build(e[x].r, mid + 1, r);
}

inline bool Modify(int &x, int l, int r, int p)
{
    int y = x; e[x = ++ tot] = e[y];
    if (l == r)
        return e[x].h.xx ^= 1, e[x].h.yy ^= 1;
    int mid = l + r >> 1, ret = p <= mid ? Modify(e[x].l, l, mid, p) : Modify(e[x].r, mid + 1, r, p);
    e[x].h.xx = (1LL * e[e[x].l].h.xx * pw1[r - mid] + e[e[x].r].h.xx) % mod1;
    e[x].h.yy = (1LL * e[e[x].r].h.yy * pw2[r - mid] + e[e[x].r].h.yy) % mod2;
    return ret;
}

inline int Cmp(int x, int y, int l, int r)
{
    if (e[x].h == e[y].h)
        return 0;
    if (l == r)
        return e[x].h.xx ? 1 : -1;
    int mid = l + r >> 1;
    if (e[e[x].l].h == e[e[y].l].h)
        return Cmp(e[x].r, e[y].r, mid + 1, r);
    return Cmp(e[x].l, e[y].l, l, mid);
}

inline int Lcp(int x, int y, int l, int r)
{
    if (e[x].h == e[y].h)
        return r - l + 1;
    if (l == r)
        return 0;
    int mid = l + r >> 1;
    if (e[e[x].l].h != e[e[y].l].h)
        return Lcp(e[x].l, e[y].l, l, mid);
    return mid - l + 1 + Lcp(e[x].r, e[y].r, mid + 1, r);
}

struct Info
{
    int r;
    bool operator < (const Info &b) const { return Cmp(r, b.r, 1, n) < 0; }
};

set <Info> S; 

inline void Sol()
{
    tot = cnt = 0; ans = 1; S.clear();
    n = Read(), Q = Read();
    pw1[0] = pw2[0] = 1;
    for (int i = 1; i <= n; i ++)
        pw1[i] = 1LL * pw1[i - 1] * bas1 % mod1, pw2[i] = 1LL * pw2[i - 1] * bas2 % mod2;
    Build(rt[0], 1, n);
    for (int i = 1; i <= Q; i ++)
    {
        char opt[5];
        scanf("%s", opt);
        if (opt[0] == '!')
        {
            int x = n - Read(); cnt ++;
            rt[cnt] = rt[cnt - 1];
            while (!Modify(rt[cnt], 1, n, x) && x > 1)
                x --;
            Info tmp; tmp.r = rt[cnt];
            if (S.empty())
                ans += n;
            else
            {
                auto it = S.lower_bound(tmp), jt = it;
                if (it == S.end())
                    jt --, ans += n - Lcp(rt[cnt], jt -> r, 1, n);
                else if (it == S.begin())
                    ans += n - Lcp(rt[cnt], it -> r, 1, n);
                else
                {
                    jt --;
                    ans += Lcp(it -> r, jt -> r, 1, n);
                    ans += n;
                    ans -= Lcp(rt[cnt], it -> r, 1, n);
                    ans -= Lcp(rt[cnt], jt -> r, 1, n);
                }
            }
            S.insert(tmp);
        }
        else
            printf("%lld\n", ans);
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Sol();
    return 0;
}

FLOWERPO

如果C=1是很显然的斜率优化。
我们尝试让两边独立,但两边显然不独立,比如 1,2,12,16,100 C=3 ,这里 16 的半径至少是 84 ,显然左边就被覆盖完了。
我们发现这种使得两边独立的操作只会有一次,并且之前一定是从 C 朝这个方向引爆。
那么我们预处理前缀,后缀的DP值,和C出发向前向后的DP值,接下来可以 O(N2B) 地枚举在哪里让两边独立,直接查询一下DP值就可以了。
当然这个DP还可以斜率优化。

#include <bits/stdc++.h>
#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 = 3005;

int n, m, b, c, a[MAXN], s[MAXN], nxt[MAXN][MAXN];
LL f[MAXN][MAXN], g[MAXN][MAXN], ans;

inline void Dp(int t)
{
    static int q[MAXN], ql, qr;
    static LL y[MAXN];
    q[ql = qr = 1] = 0;
    for (int i = 1; i <= m; i ++)
    {
        while (ql < qr && y[q[ql + 1]] - y[q[ql]] < 2LL * s[i] * (s[q[ql + 1]] - s[q[ql]]))
            ql ++;
        f[t][i] = f[t - 1][q[ql]] + 1LL * (s[i] - s[q[ql]]) * (s[i] - s[q[ql]]);
        y[i] = f[t - 1][i] + 1LL * s[i] * s[i];
        while (ql < qr && (__int128)(y[i] - y[q[qr]]) * (s[q[qr]] - s[q[qr - 1]]) <= (__int128)(y[q[qr]] - y[q[qr - 1]]) * (s[i] - s[q[qr]]))
            qr --;
        q[++ qr] = i;
    }
}

inline int Sol()
{
    n = Read(), b = Read(), c = Read() - 1; ans = 1LL << 60;
    for (int i = 0; i < n; i ++)
        a[i] = Read();
    for (int i = 0; i < n; i ++)
        for (int j = 1, l = i, r = i; j < n; nxt[i][j ++] = l * n + r)
            if (l && (r == n - 1 || a[i] - a[l] <= a[r] - a[i]))
                l --;
            else
                r ++;
    for (int i = 1; i <= n; i ++)
        f[0][i] = 1LL << 60;
    m = 0;
    for (int i = 1; i < n; i ++)
        s[++ m] = a[i] - a[0];
    for (int i = 1; i <= b; i ++)
        Dp(i);
    for (int i = 0; i < c; i ++)
        for (int j = 0; j <= b; j ++)
            g[i][j] = f[j][i];
    m = 0;
    for (int i = n - 2; ~i; i --)
        s[++ m] = a[n - 1] - a[i];
    for (int i = 1; i <= b; i ++)
        Dp(i);
    for (int i = n - 1; i > c; i --)
        for (int j = 0; j <= b; j ++)
            g[i][j] = f[j][n - 1 - i];
    m = 0;
    for (int i = c - 1; ~i; i --)
        s[++ m] = a[c] - a[i];
    for (int i = 1; i <= b; i ++)
        Dp(i);
    for (int i = c - 1; ~i; i --)
        for (int j = 1; j < n; j ++)
            for (int k = 1; k < b; k ++)
            {
                int l = nxt[i][j] / n, r = nxt[i][j] - l * n, val = max(a[i] - a[l], a[r] - a[i]);
                if ((l < i || !l) && (r > c || r == n - 1))
                    ans = min(ans, f[k][c - i] + 1LL * val * val + g[l][b - k - 1] + g[r][b - k - 1]);
            }
    m = 0;
    for (int i = c + 1; i < n; i ++)
        s[++ m] = a[i] - a[c];
    for (int i = 1; i <= b; i ++)
        Dp(i);
    for (int i = c + 1; i < n; i ++)
        for (int j = 1; j < n; j ++)
            for (int k = 1; k < b; k ++)
            {
                int l = nxt[i][j] / n, r = nxt[i][j] - l * n, val = max(a[i] - a[l], a[r] - a[i]);
                if ((l < c || !l) && (r > i || r == n - 1))
                    ans = min(ans, f[k][i - c] + 1LL * val * val + g[l][b - k - 1] + g[r][b - k - 1]);
            }
    for (int i = 0; i < n; i ++)
    {
        int l = nxt[c][i] / n, r = nxt[c][i] - l * n, val = max(a[c] - a[l], a[r] - a[c]);
        if ((l < c || !l) && (r > c || r == n - 1))
            ans = min(ans, 1LL * val * val + g[l][b - 1] + g[r][b - 1]);
    }
    printf("%lld\n", ans);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Sol();
    return 0;
}

Challenge是个工业题,懒得写了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值