HNOI2014解题报告

8 篇文章 0 订阅
6 篇文章 0 订阅

HNOI2014解题报告

Author: Pengyihao

Day1 T1 画框


思路

这个题目我其实是没有思路的。

网上说要用一种高深的最小乘积生成树的算法,我就学了一下。

我们把每一种搭配方案中, A 的和记做 x B 的和记做 y

那么一种搭配方案就可以看做一个坐标 (x,y)

因为 disharmony=xy ,所以我们可以把 disharmony 看作反比例函数的 k

因为反比例函数越靠近原点,k 越小。

所以我们要 (x,y) 尽可能靠近原点。

找到 x 最小的方案 l,和 y 最小的方案 r,分别求出它们的坐标。

为什么大家都用KM算法,就我用费用流?好怕怕啊

然后我们就要找到在这两个方案的坐标的连线的下方,且三个方案形成的三角形面积最大的方案。

这个面积用叉积可以计算,最后发现形如 aA+bB ,其中 A,B 是题目中的那个东西。

于是我们可以再跑一遍费用流求出这个方案 mid

递归处理 (l,mid) (mid,r)

边界就是 l==mid||mid==r

这个据说递归次数期望是 lnn ,然后复杂度就对了。


代码
#include <bits/stdc++.h>

typedef long long LL;

#define FOR(i, a, b) for (LL i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (LL i = (a), i##_END_ = (b); i >= i##_END_; i--)

template <typename Tp> void in(Tp &x) {
    char ch = getchar(); x = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}

template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}

const LL MAXN = 80;

LL n, A[MAXN][MAXN], B[MAXN][MAXN], tmp[MAXN][MAXN];

namespace KM
{
    using std::queue; queue<LL>q;
    bool in_stack[MAXN << 1];

    const LL ss = 0, tt = 159;

    LL cnt, ret1, ret2, dis[MAXN << 1], pre[MAXN << 1];
    LL head[MAXN << 1], data[MAXN * MAXN << 2], flow[MAXN * MAXN << 2];
    LL wei1[MAXN * MAXN << 2], wei2[MAXN * MAXN << 2], nxt[MAXN * MAXN << 2], wei[MAXN * MAXN << 2];

    void add(LL x, LL y, LL z, LL l, LL l1, LL l2)
    {
        nxt[cnt] = head[x]; data[cnt] = y; flow[cnt] = z;
        wei[cnt] = l; wei1[cnt] = l1; wei2[cnt] = l2; head[x] = cnt++;

        nxt[cnt] = head[y]; data[cnt] = x; flow[cnt] = 0;
        wei[cnt] =-l; wei1[cnt] =-l1; wei2[cnt] =-l2; head[y] = cnt++;
    }

    bool bfs()
    {
        memset(pre, -1, sizeof pre);
        memset(dis, 0x3f, sizeof dis);
        dis[ss] = 0; q.push(ss); in_stack[ss] = true;

        while (!q.empty()) {
            LL now = q.front(); q.pop();
            in_stack[now] = false;
            for (LL i = head[now]; i != -1; i = nxt[i]) {
                if (flow[i] && dis[data[i]] > dis[now] + wei[i]) {
                    dis[data[i]] = dis[now] + wei[i];
                    pre[data[i]] = i;
                    if (!in_stack[data[i]]) {
                        in_stack[data[i]] = true;
                        q.push(data[i]);
                    }
                }
            }
        }

        return pre[tt] != -1;
    }

    void dfs()
    {
        for (LL i = tt; pre[i] != -1; i = data[pre[i] ^ 1]) ret1 += wei1[pre[i]];
        for (LL i = tt; pre[i] != -1; i = data[pre[i] ^ 1]) ret2 += wei2[pre[i]];
        for (LL i = tt; pre[i] != -1; i = data[pre[i] ^ 1]) flow[pre[i]]--, flow[pre[i] ^ 1]++;
    }

    std::pair<LL, LL>main(LL argv[MAXN][MAXN])
    {
        ret1 = ret2 = 0; cnt = 0;
        memset(head, -1, sizeof head);
        FOR(i, 1, n) add(ss, i, 1, 0, 0, 0);
        FOR(i, 1, n) FOR(j, 1, n) {
            add(i, j + n, 1, argv[i][j], A[i][j], B[i][j]);
        }
        FOR(i, 1, n) add(i + n, tt, 1, 0, 0, 0);
        while (bfs()) dfs();
        return std::make_pair(ret1, ret2);
    }
}

bool gongxian(std::pair<LL, LL>l, std::pair<LL, LL>mid, std::pair<LL, LL>r)
{
    return (l.second - r.second) * (l.first - mid.first) == (l.second - mid.second) * (l.first - r.first);
}

LL get_ans(std::pair<LL, LL>l, std::pair<LL, LL>r)
{
    if (l.first == r.first || l.second == r.second)
        return Min(l.first * l.second, r.first * r.second);
    FOR(i, 1, n) FOR(j, 1, n)
        tmp[i][j] = -((r.second - l.second) * A[i][j] + (l.first - r.first) * B[i][j]);
    std::pair<LL, LL>mid = KM::main(tmp);
    if (gongxian(l, mid, r)) return Min(l.first * l.second, r.first * r.second);
    return Min(get_ans(l, mid), get_ans(mid, r));
}

int main()
{
    freopen("frame.in", "r", stdin);
    freopen("frame.out", "w", stdout);

    LL tcase; in(tcase);

    while (tcase--) {
        in(n);
        FOR(i, 1, n) FOR(j, 1, n) in(A[i][j]);
        FOR(i, 1, n) FOR(j, 1, n) in(B[i][j]);
        std::pair<LL, LL>retA = KM::main(A), retB = KM::main(B);
        printf("%lld\n", get_ans(retA, retB));
    }

    return 0;
}

Day1 T2 世界树


思路

这也是我没学过的算法——虚树。

首先用单调栈维护右链,把虚树构建出来;

然后对于虚树上的每条边,把它的分界点找出来,然后分段赋给管理端点的那两个点。

注意判断管理端点的两个点相同的情况。

这个题目的构建虚树需要用lca,我用了倍增。

这个题目找到分界点也需要用倍增。

没有使用数据结构,代码却比数据结构题还要长。


代码
#include <bits/stdc++.h>

typedef long long LL;

#define debug(...) fprintf(stderr, __VA_ARGS__)

#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)

template <typename Tp> void in(Tp &x) {
    char ch = getchar(); x = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}

template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}

const int MAXN = 300010;

bool is_chs[MAXN];

int n, q, num[MAXN], fa[MAXN], dfn[MAXN], sa[MAXN], depth[MAXN], sz[MAXN];
int INDEX, cnt, head[MAXN], data[MAXN << 1], nxt[MAXN << 1], log_num[1000010];

int anc[MAXN][20], xsz[MAXN], val[MAXN];

void add(int x, int y)
{
    nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++;
    nxt[cnt] = head[y]; data[cnt] = x; head[y] = cnt++;
}

void dfs(int now, int pa)
{
    sz[now] = 1;
    depth[now] = depth[pa] + 1;
    fa[now] = pa; dfn[now] = ++INDEX;
    for (int i = head[now]; i != -1; i = nxt[i]) {
        if (data[i] != pa) {
            dfs(data[i], now);
            sz[now] += sz[data[i]];
        }
    }
}

void dfs_anc(int now, int pa)
{
    anc[now][0] = pa;
    for (int i = 1; anc[now][i - 1] != -1; i++) {
        anc[now][i] = anc[anc[now][i - 1]][i - 1];
    }
    for (int i = head[now]; i != -1; i = nxt[i]) {
        if (data[i] != pa) dfs_anc(data[i], now);
    }
}

namespace get_lca
{
    int eula[MAXN * 3], st[MAXN], ed[MAXN], IND, to[MAXN];
    int minx[MAXN * 3][21];

    void dfs2(int now)
    {
        eula[++eula[0]] = ++IND;
        st[now] = eula[0]; to[IND] = now;
        for (int i = head[now]; i != -1; i = nxt[i]) {
            if (data[i] != fa[now]) {
                dfs2(data[i]);
                eula[++eula[0]] = eula[st[now]];
            }
        }
        ed[now] = eula[0];
    }

    int lca(int x, int y)
    {
        if (!x || !y) return 0;
        if (st[x] > ed[y]) std::swap(x, y); x = st[x]; y = ed[y];
        int delta = log_num[y - x + 1];
        return to[Min(minx[x][delta], minx[y - (1 << delta) + 1][delta])];
    }

    void start()
    {
        FOR(i, 1, eula[0]) minx[i][0] = eula[i];
        FOR(i, 1, 20) {
            FOR(j, 1, eula[0]) {
                if (j + (1 << i) - 1 > eula[0]) break;
                minx[j][i] =
                    Min(minx[j][i - 1], minx[j + (1 << (i - 1))][i - 1]);
            }
        }
        FOR(i, 1, 1000000) log_num[i] = log2(i);
    }
}

int stack[MAXN], top, in_tree[MAXN];
int head_xu[MAXN], cnt_xu, nxt_xu[MAXN << 1], data_xu[MAXN << 1];

namespace build_tree
{
    void add_xu(int x, int y)
    {
        nxt_xu[cnt_xu] = head_xu[x]; data_xu[cnt_xu] = y; head_xu[x] = cnt_xu++;
        nxt_xu[cnt_xu] = head_xu[y]; data_xu[cnt_xu] = x; head_xu[y] = cnt_xu++;
    }

    bool cmp(int x, int y)
    {
        return dfn[x] < dfn[y];
    }

    void builds_tree()
    {
        cnt_xu = 0;
        stack[top = 1] = 0;
        in_tree[0] = 0;
        FOR(i, 1, num[0]) {
            is_chs[num[i]] = true;
            in_tree[++in_tree[0]] = num[i];
        }
        in_tree[++in_tree[0]] = 0;
        std::sort(in_tree + 1, in_tree + in_tree[0] + 1, cmp);
        int now_in_tree = in_tree[0];
        FOR(i, 2, now_in_tree) {
            int now = in_tree[i];
            int anc = get_lca::lca(stack[top], now);
            if (anc == stack[top]) stack[++top] = now;
            else {
                while (true) {
                    int tp = stack[top], tp_l = stack[top - 1];
                    if (tp_l == anc) {
                        add_xu(tp_l, tp); top--; break;
                    }
                    else if (dfn[tp_l] > dfn[anc]) {
                        add_xu(tp_l, tp); top--;
                    }
                    else {
                        in_tree[++in_tree[0]] = anc;
                        add_xu(anc, tp); stack[top] = anc; break;
                    }
                }
                stack[++top] = now;
            }
        }
        while (top != 1) {
            add_xu(stack[top - 1], stack[top]); top--;
        }
    }
}

namespace find_father
{
    int find(int x, int y)
    {
        for (int i = 19; i >= 0; i--) {
            if (y & (1 << i)) {
                x = anc[x][i];
            }
        }
        return x;
    }
}

namespace DP
{

    int f[MAXN][2], g[MAXN][2], ret[MAXN];

    void dp1(int now, int pa)
    {
        val[now] = 0;
        xsz[now] = 1;
        f[now][0] = is_chs[now] ? 0 : 0x3f3f3f3f;
        f[now][1] = now;
        for (int i = head_xu[now]; i != -1; i = nxt_xu[i]) {
            if (data_xu[i] != pa) {
                dp1(data_xu[i], now);
                xsz[now] += xsz[data_xu[i]];
                int frm = depth[data_xu[i]] - depth[now];
                if (f[now][0] > f[data_xu[i]][0] + frm ||
                    f[now][0] == f[data_xu[i]][0] + frm &&
                    f[now][1] > f[data_xu[i]][1])
                {
                    f[now][1] = f[data_xu[i]][1];
                    f[now][0] = f[data_xu[i]][0] + frm;
                }
            }
        }
    }

    void dp2(int now, int pa)
    {
        g[now][0] = f[now][0];
        g[now][1] = f[now][1];
        if (pa != -1) {
            int frm = depth[now] - depth[pa];
            if (g[now][0] > g[pa][0] + frm ||
                g[now][0] == g[pa][0] + frm && g[now][1] > g[pa][1])
            {
                g[now][1] = g[pa][1]; g[now][0] = g[pa][0] + frm;
            }
        }
        for (int i = head_xu[now]; i != -1; i = nxt_xu[i]) {
            if (data_xu[i] != pa) dp2(data_xu[i], now);
        }
    }

    int getr(int x, int y, int z, bool t)
    {
        if (y - x + z < 0) return 0;
        if (t) return (y - x + z) / 2;
        else {
            if ((y - x + z) % 2 == 0) return (y - x + z) / 2;
            else return (y - x + z) / 2 + 1;
        }
    }

    void dp3(int now, int pa)
    {
        if (!pa) {
            ret[g[now][1]] += n - sz[now];
        }
        bool flag = false;
        for (int i = head_xu[now]; i != -1; i = nxt_xu[i])
            if (data_xu[i] != pa) {
                flag = true;
                int nnum = data_xu[i], all;
                if (now) {
                    all = depth[nnum] - depth[now] - 1;
                    if (g[now][1] == g[nnum][1]) {
                        if (all) {
                            int pos = find_father::find(nnum, all);
                            ret[g[now][1]] += sz[pos] - sz[nnum];
                            val[now] -= sz[pos];
                        }
                        else val[now] -= sz[nnum];
                    }
                    else {
//                    ret[g[now][1]] += getr(g[now][0], g[nnum][0], all,
//                                           g[now][1] > g[nnum][1]);
//                    ret[g[nnum][1]] += getr(g[nnum][0], g[now][0], all,
//                                            g[nnum][1] > g[now][1]);
                        if (!all) {
                            val[now] -= sz[nnum];
                        }
                        else {
                            int Anc = getr(g[nnum][0], g[now][0], all,
                                           g[nnum][1] > g[now][1]);
                            int pos = find_father::find(nnum, Anc);
                            ret[g[nnum][1]] += sz[pos] - sz[nnum];

                            int pos2 = find_father::find(nnum, all);
                            ret[g[now][1]] += sz[pos2] - sz[pos];
                            val[now] -= sz[pos2];
                        }
                    }
                }
                dp3(nnum, now);
            }
    }

    void dp4(int now, int pa)
    {
        if (now) ret[g[now][1]] += sz[now] + val[now];
        for (int i = head_xu[now]; i != -1; i = nxt_xu[i]) {
            if (data_xu[i] != pa) dp4(data_xu[i], now);
        }
    }

    void work()
    {
        build_tree::builds_tree();
        FOR(i, 1, num[0]) ret[num[i]] = 0;
        dp1(0, -1); dp2(0, -1); dp3(0, -1); dp4(0, -1);
        FOR(i, 1, num[0]) printf("%d ", ret[num[i]]);
        putchar(10);
    }
}

int main()
{
    freopen("worldtree.in", "r", stdin);
    freopen("worldtree.out", "w", stdout);

    memset(head, -1, sizeof head);
    memset(head_xu, -1, sizeof head_xu);

    in(n);
    FOR(i, 1, n - 1) {
        int x, y; in(x); in(y); add(x, y);
    }

    memset(anc, -1, sizeof anc);

    dfs(1, 0); dfs_anc(1, 0);
    get_lca::dfs2(1); get_lca::start();
    FOR(i, 1, n) sa[dfn[i]] = i;

    in(q);
    FOR(i, 1, q) {
        FOR(i, 1, num[0])
            is_chs[num[i]] = false;
        FOR(i, 1, in_tree[0])
            head_xu[in_tree[i]] = -1;
        in(num[0]);
        FOR(j, 1, num[0]) in(num[j]);
        DP::work();
    }

    return 0;
}

Day1 T3 米特运输


思路

根据每个点的权值,计算出根节点的权值。

然后用 n 根节点权值的众数即可。

因为数据太大,所以需要取对数。


代码
#include <bits/stdc++.h>

typedef long long LL;

#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)

template <typename Tp> void in(Tp &x) {
    char ch = getchar(), f = 1; x = 0;
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    x *= f;
}

template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}

const int MAXN = 500010;

long double rot[MAXN], val[MAXN];
int n, w[MAXN], tot[MAXN];
int cnt, head[MAXN], data[MAXN << 1], nxt[MAXN << 1];

void add(int x, int y)
{
    nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++;
    nxt[cnt] = head[y]; data[cnt] = x; head[y] = cnt++;
}

void dfs1(int now, int pa)
{
    for (int i = head[now]; i != -1; i = nxt[i])
        if (data[i] != pa) {
            tot[now]++;
            dfs1(data[i], now);
        }
}

void dfs2(int now, int pa)
{
    for (int i = head[now]; i != -1; i = nxt[i]) {
        if (data[i] != pa) {
            val[data[i]] = log(tot[now]) + val[now];
            dfs2(data[i], now);
        }
    }
}

const long double eps = 1e-6;

int main()
{
    freopen("meat.in", "r", stdin);
    freopen("meat.out", "w", stdout);

    memset(head, -1, sizeof head);

    in(n);
    FOR(i, 1, n) in(w[i]);
    FOR(i, 1, n - 1) {int u, v; in(u); in(v); add(u, v);}
    dfs1(1, 0); dfs2(1, 0);
    FOR(i, 1, n) rot[i] = val[i] + log(w[i]);

    std::sort(rot + 1, rot + n + 1);

    int ret = 0, line = 0;
    FOR(i, 1, n) {
        if (i == 1 || fabs(rot[i] - rot[i - 1]) > eps) {
            chkmax(ret, line);
            line = 1;
        }
        else line++;
    }

    chkmax(ret, line);
    printf("%d\n", n - ret);

    return 0;
}

Day2 T1 抄卡组


思路

首先,如果所有的字符串都有通配符,那么只需要两两比较前缀和后缀即可。

就是按每个字符串不包含通配符的最大前缀长度进行排序,比较一遍;

然后按每个字符串不包含通配符的最大后缀长度进行排序,比较一边。

如果所有的字符串都没有通配符,那么只需要比较hash值就可以了。

如果有些有通配符,有些没有通配符,将没有通配符的进行比较,看是否相同。

然后对于有通配符的,将通配符视作分隔符,即把原串分为一段一段的,分开进行匹配。

注意有通配符的字符串和没有通配符的字符串的首尾要对应。


代码
#include <bits/stdc++.h>

typedef long long LL;
typedef unsigned long long ULL;

#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)

template <typename Tp> void in(Tp &x) {
    char ch = getchar(), f = 1; x = 0;
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    x *= f;
}

template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}

const int MAXN = 2000010;

using std::string;
using std::cin;
using std::cout;

string str[MAXN];
int t, n, len[MAXN];
ULL hs[MAXN];
const ULL BASE = 31;

int prefix[MAXN], suffix[MAXN], numb[MAXN];

void gethash(int num)
{
    hs[num] = 0;
    FOR(i, 0, len[num] - 1) {
        hs[num] = hs[num] * BASE + str[num][i];
    }
}

bool isop[MAXN];
int nopera[MAXN];

ULL rhs[MAXN], po[MAXN];

ULL power(ULL x, ULL y)
{
    if (!y) return 1;
    return po[y];
}

void work()
{
    string *a = str;

    FOR(i, 1, nopera[0])
        isop[nopera[i]] = false;

    nopera[0] = 0;

    FOR(i, 1, n) {
        bool flag = true;
        FOR(j, 0, len[i] - 1) {
            if (str[i][j] == '*') {
                flag = false;
                break;
            }
        }
        if (flag) {
            isop[i] = true;
            nopera[++nopera[0]] = i;
        }
    }
    FOR(i, 2, nopera[0]) {
        if (hs[nopera[i]] != hs[nopera[i - 1]]) {
            puts("N");
            return;
        }
    }

    int need_compare = nopera[1];
    ULL TBASE = 1;

    FOR(i, 1, len[need_compare]) {
        rhs[i] = rhs[i - 1] + str[need_compare][i - 1] * TBASE;
        TBASE = TBASE * BASE;
    }

    FOR(i, 1, n) if (!isop[i]) {
        int lastpos = 0;
        for (int j = 0, k; j <= len[i] - 1; j = k + 1) {
            k = j;
            while (k < len[i] && str[i][k] == '*') k++;

            j = k;
            while (k < len[i] && str[i][k] != '*') k++; k--;

            if (str[i][k] == '*') break;

            ULL nowhs = 0, TBASE = 1;
            FOR(l, j, k) {
                nowhs = nowhs + str[i][l] * TBASE;
                TBASE = TBASE * BASE;
            }

            while (true) {
                if (lastpos + (k - j + 1) > len[need_compare]) {
                    puts("N");
                    return;
                }
                if (k == len[i] - 1) {
                    lastpos = len[need_compare] - (k - j + 1);
                }
                ULL tmpnow = nowhs;
                if (rhs[lastpos + (k - j + 1)] - rhs[lastpos] == tmpnow * power(31, lastpos)) {
                    lastpos += (k - j + 1);
                    break;
                }
                if (j != 0) {
                    lastpos++;
                }
                else {
                    puts("N");
                    return;
                }
            }
        }
    }
    puts("Y");
}

bool cmp_prefix(int x, int y)
{
    return prefix[x] < prefix[y];
}

bool cmp_suffix(int x, int y)
{
    return suffix[x] < suffix[y];
}

int main()
{
    freopen("hs.in", "r", stdin);
    freopen("hs.out", "w", stdout);

    po[0] = 1;
    FOR(i, 1, 2000000) po[i] = po[i - 1] * BASE;

    std::ios::sync_with_stdio(false);  
    cin >> t;
    while (t--) {
        cin >> n;
        FOR(i, 1, n) cin >> str[i], len[i] = str[i].size();

        bool isy = true, isn = true;
        FOR(i, 1, n) {
            gethash(i);
            bool iss = false;
            FOR(j, 0, len[i] - 1) {
                if (str[i][j] == '*') isn = false, iss = true;
            }
            if (!iss) isy = false;
        }

        if (isn) {
            bool flag = false;
            FOR(i, 2, n) if (hs[i] != hs[i - 1]) {
                flag = true;
                break;
            }
            if (!flag) puts("Y");
            else puts("N");
            continue;
        }

        else if (isy) {
            FOR(i, 1, n) {
                FOR(j, 0, len[i] - 1) {
                    if (str[i][j] == '*') {
                        prefix[i] = j; break;
                    }
                }
                DNF(j, len[i] - 1, 0) {
                    if (str[i][j] == '*') {
                        suffix[i] = len[i] - 1 - j; break;
                    }
                }
            }
            bool flag = true;
            FOR(i, 1, n) numb[i] = i;
            std::sort(numb + 1, numb + n + 1, cmp_prefix);
            FOR(i, 2, n) {
                int last = numb[i - 1], now = numb[i];
                FOR(j, 1, prefix[last]) {
                    if (str[last][j - 1] != str[now][j - 1]) {
                        flag = false; puts("N"); break;
                    }
                }
                if (!flag) break;
            }
            if (!flag) continue;
            std::sort(numb + 1, numb + n + 1, cmp_suffix);
            FOR(i, 2, n) {
                int last = numb[i - 1], now = numb[i];
                FOR(j, 1, suffix[last]) {
                    if (str[last][len[last] - j] != str[now][len[now] - j]) {
                        flag = false; puts("N"); break;
                    }
                }
                if (!flag) break;
            }
            if (flag) puts("Y");
            continue;
        }

        else {
            work();
        }
    }
    return 0;
}

Day2 T2 道路堵塞


这是一道玄学题,需要依赖splay的复杂度的不确定性进行解题。

所以我跳过了它。


Day2 T3 江南乐


思路

首先用SG函数就可以做到 O(n2) (枚举分开的情况,然后用朴素的统计就行了)

然后因为这题是分石子,我们可以发现分出来的石子很多都是一样的。

其实只可能分出两种石子,大小为 nmodi 的,和大小为 inmodi 的。

根据数量的奇偶性,最终会被消成不超过两个。

因为只关注奇偶性,所以对于 n/i 相等的多种分法,只需要计算最小的 i i+1 两种即可。

复杂度为 O(nn)


代码
#include <bits/stdc++.h>

typedef long long LL;

#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)

template <typename Tp> void in(Tp &x) {
    char ch = getchar(), f = 1; x = 0;
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    x *= f;
}

template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}

const int MAXN = 100010;

int t, f, sg[MAXN], can[MAXN];

int main()
{
    freopen("game.in", "r", stdin);
    freopen("game.out", "w", stdout);

    in(t); in(f);
    FOR(i, 0, f - 1) sg[i] = 0;
    FOR(i, f, 100000) {
        for (int j = 2, k; j <= i; j = k + 1) {
            k = i / (i / j);
            int s1 = j, s2 = j + 1;
            int a = ((i % s1) & 1) ? (i / s1 + 1) : 0;
            int b = ((s1 - (i % s1)) & 1) ? (i / s1) : 0;
            can[sg[a] ^ sg[b]] = i;
            a = ((i % s2) & 1) ? (i / s2 + 1) : 0;
            b = ((s2 - (i % s2)) & 1) ? (i / s2) : 0;
            can[sg[a] ^ sg[b]] = i;
        }
        FOR(j, 0, 100000)
            if (can[j] != i) {
                sg[i] = j;
                break;
            }
    }
    FOR(i, 1, t) {
        int n, ret = 0; in(n);
        FOR(j, 1, n) {
            int x; in(x); ret ^= sg[x];
        }
        if (ret) printf("1");
        else printf("0");
        if (i != t) printf(" ");
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值