HNOI2014解题报告

来源:互联网 发布:诸暨行知小学怎么样 编辑:程序博客网 时间:2024/05/21 00:48

HNOI2014解题报告

Author: Pengyihao


Day1 T1 画框


思路

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

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

我们把每一种搭配方案中,A 的和记做 xB 的和记做 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 相等的多种分法,只需要计算最小的 ii+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;}
原创粉丝点击