清华集训2017补题

Day 1

tree

首先考虑 m=1 怎么做,显然 di=2n2 ,我们不管它。

bi 表示 i prufer序列中出现次数,那么有

ans=(2n2)(n2)!ni=1aini=1bi=2n2ni=1abii(bi+1)bi!

暴力展开 ni=1(bi+1) ,考虑计算一个子序列 bj1,bj2...,bjk

注意到提取出来的 b 可以和分母的b!消掉变成 (b1)! ,那么我们这样做之后,其贡献为:

kl=1ajlni=1bi=n2kni=1abiibi!=(kl=1ajl)(ai)nk2(nk2)!

考虑回到原问题, (bi+1)m=(bi1+2)m1bi+(bi+1)m1 ,第一部分的 bi 类似于 m=1 提到外面跟阶乘消掉,相当于 bi 减去一,提取东西的个数加上一,同时外面系数乘上 ai ,第二部分不变,将这个东西视为一个 m 次多项式,分治NTT即可。

dmi 相当于有一个是 2m 次多项式,直接处理掉就好了。

#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 = 65540;
const int MAXM = 65;
const int mod = 998244353;
const int G = 3;

int n, m, a[MAXN], fac[MAXN], inv[MAXN], f[MAXM][MAXM];

inline int Qow(int x, int y)
{
    int r = 1;
    for (; y; y >>= 1, x = 1LL * x * x % mod)
        if (y & 1)
            r = 1LL * r * x % mod;
    return r;
}

namespace NTT
{
    int n, L, W[20], R[MAXN];

    inline void Ini(int len)
    {
        for (n = 1, L = 0; n < len; n <<= 1, L ++);
        for (int i = 1; i < n; i ++)
            R[i] = (R[i >> 1] >> 1) | ((i & 1) << L - 1);
        W[0] = Qow(G, mod - 1 >> L);
        for (int i = 1; i < L; i ++)
            W[i] = 1LL * W[i - 1] * W[i - 1] % mod;
    }

    inline void Ini_Inv()
    {
        W[0] = Qow(W[0], mod - 2);
        for (int i = 1; i < L; i ++)
            W[i] = 1LL * W[i - 1] * W[i - 1] % mod;
    }

    inline void FFT(int *x)
    {
        for (int i = 0; i < n; i ++)
            if (i < R[i])
                swap(x[i], x[R[i]]);
        for (int i = 1, l = L - 1; i < n; i <<= 1, l --)
            for (int j = 0; j < n; j += i << 1)
                for (int k = 0, w = 1, u, v; k < i; k ++, w = 1LL * w * W[l] % mod)
                    u = x[j + k], v = 1LL * x[j + k + i] * w % mod, x[j + k] = (u + v) % mod, x[j + k + i] = (u - v + mod) % mod;
    }
}

pair <vector <int>, vector <int>> Solve(int l, int r)
{
    if (l == r)
    {
        vector <int> L, R;
        int cur = 1;
        for (int i = 0; i <= m; i ++)
            L.pb(1LL * cur * f[m][i] % mod), R.pb(1LL * cur * f[m << 1][i] % mod), cur = 1LL * cur * a[l] % mod;
        for (int i = m + 1; i <= m << 1; i ++)
            R.pb(1LL * cur * f[m << 1][i] % mod), cur = 1LL * cur * a[l] % mod;
        return mp(L, R);
    }
    else
    {
        int mid = l + r >> 1;
        pair <vector <int>, vector <int>> L = Solve(l, mid), R = Solve(mid + 1, r);
        static int x[MAXN], y[MAXN], z[MAXN], w[MAXN];
        NTT::Ini(L.xx.size() + R.yy.size() - 1);
        for (int i = 0; i < NTT::n; i ++)
            x[i] = i < L.xx.size() ? L.xx[i] : 0, y[i] = i < L.yy.size() ? L.yy[i] : 0, z[i] = i < R.xx.size() ? R.xx[i] : 0, w[i] = i < R.yy.size() ? R.yy[i] : 0;
        NTT::FFT(x), NTT::FFT(y), NTT::FFT(z), NTT::FFT(w);
        for (int i = 0; i < NTT::n; i ++)
            y[i] = (1LL * x[i] * w[i] + 1LL * y[i] * z[i]) % mod, x[i] = 1LL * x[i] * z[i] % mod;
        NTT::Ini_Inv(), NTT::FFT(x), NTT::FFT(y);
        for (int i = 0, v = Qow(NTT::n, mod - 2); i < NTT::n; i ++)
            x[i] = 1LL * x[i] * v % mod, y[i] = 1LL * y[i] * v % mod;
        return mp(vector <int> (x, x + min(n - 1, (int)(L.xx.size() + R.xx.size() - 1))), vector <int> (y, y + min(n - 1, (int)(L.xx.size() + R.yy.size() - 1))));
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read(), fac[0] = fac[1] = inv[0] = inv[1] = 1;
    for (int i = 2; i <= n; i ++)
        fac[i] = 1LL * fac[i - 1] * i % mod, inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
    for (int i = 2; i <= n; i ++)
        inv[i] = 1LL * inv[i - 1] * inv[i] % mod;
    for (int i = 1; i <= n; i ++)
        a[i] = Read();
    if (n == 1)
        return puts("0"), 0;
    f[0][0] = 1;
    for (int i = 1; i <= m << 1; i ++)
        for (int j = 0; j <= i; j ++)
            f[i][j] = (1LL * f[i - 1][j] * (j + 1) + (j ? f[i - 1][j - 1] : 0)) % mod;
    vector <int> ret = Solve(1, n).yy;
    int ans = 0, sum = 0, cur = 1;
    for (int i = 1; i <= n; i ++)
        sum = (sum + a[i]) % mod;
    for (int i = n - 2; ~i; i --)
        ans = (1LL * cur * ret[i] % mod * inv[n - i - 2] + ans) % mod, cur = 1LL * cur * sum % mod;
    for (int i = 1; i <= n; i ++)
        ans = 1LL * ans * a[i] % mod;
    ans = 1LL * ans * fac[n - 2] % mod;
    return printf("%d\n", ans), 0;
}

infinityloop

将网格看成二分图,相当于插头需要匹配。

每个格子再拆四个点,然后上费用流就好了。

建图可以自己推推。

#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;
}

namespace Flow
{
    const int MAXN = 10005;
    const int MAXM = 1000005;
    const int INF = 0x3f3f3f3f;

    struct Edge
    {
        int p, v, w, c;
    } e[MAXM];

    int S, T, e_cnt = 1, hed[MAXN], dis[MAXN];
    bool vis[MAXN];

    inline void Addedge(int x, int y, int w, int c)
    {
        e[++ e_cnt] = {y, hed[x], w, c}, hed[x] = e_cnt;
        e[++ e_cnt] = {x, hed[y], 0, -c}, hed[y] = e_cnt;
    }

    inline bool SPFA()
    {
        queue <int> q;
        for (int i = 1; i <= T; i ++)
            dis[i] = INF, vis[i] = 0;
        q.push(S);
        while (!q.empty())
        {
            int x = q.front();
            q.pop(), vis[x] = 0;
            for (int i = hed[x]; i; i = e[i].v)
                if (e[i].w && dis[e[i].p] > dis[x] + e[i].c)
                    if (dis[e[i].p] = dis[x] + e[i].c, !vis[e[i].p])
                        vis[e[i].p] = 1, q.push(e[i].p);
        }
        return dis[T] ^ INF;
    }

    inline int DFS(int x, int f)
    {
        vis[x] = 1;
        if (x == T)
            return f;
        int r = 0, d;
        for (int i = hed[x]; i; i = e[i].v)
            if (!vis[e[i].p] && e[i].w && dis[e[i].p] == dis[x] + e[i].c)
            {
                d = DFS(e[i].p, min(f - r, e[i].w));
                e[i].w -= d, e[i ^ 1].w += d, r += d;
                if (r == f)
                    return r;
            }
        return r;
    }

    inline pii Solve()
    {
        int x = 0, y = 0, z = 0;
        while (SPFA())
            for (vis[T] = 1; vis[T]; z = DFS(S, INF), x += z, y += z * dis[T])
                for (int i = 0; i <= T; i ++)
                    vis[i] = 0;
        return mp(x, y);
    }
}

const int MAXN = 2005;

int n, m, cnt, a[MAXN][MAXN], idx[MAXN][MAXN][5];

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    using namespace Flow;
    n = Read(), m = Read(), T = n * m * 5 + 1;
    int l = 0, r = 0;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
        {
            a[i][j] = Read();
            if (i + j & 1)
                l += __builtin_popcount(a[i][j]);
            else
                r += __builtin_popcount(a[i][j]);
        }
    if (l ^ r)
        return puts("-1"), 0;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            for (int k = 0; k <= 4; k ++)
                idx[i][j][k] = ++ cnt;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            if (i + j & 1)
            {
                Addedge(S, idx[i][j][4], __builtin_popcount(a[i][j]), 0);
                if (a[i][j] == 1 || a[i][j] == 2 || a[i][j] == 4 || a[i][j] == 8)
                {
                    for (int k = 0; k < 4; k ++)
                        if (a[i][j] >> k & 1)
                            Addedge(idx[i][j][4], idx[i][j][k], 1, 0), Addedge(idx[i][j][k], idx[i][j][k ^ 1], 1, 1), Addedge(idx[i][j][k], idx[i][j][k ^ 2], 1, 2), Addedge(idx[i][j][k], idx[i][j][k ^ 3], 1, 1);
                }
                else if (a[i][j] == 3 || a[i][j] == 6 || a[i][j] == 12 || a[i][j] == 9)
                {
                    for (int k = 0; k < 4; k ++)
                        if (a[i][j] >> k & 1)
                            Addedge(idx[i][j][4], idx[i][j][k], 1, 0), Addedge(idx[i][j][k], idx[i][j][k ^ 2], 1, 1);
                }
                else if (a[i][j] == 5 || a[i][j] == 10 || a[i][j] == 15)
                {
                    for (int k = 0; k < 4; k ++)
                        if (a[i][j] >> k & 1)
                            Addedge(idx[i][j][4], idx[i][j][k], 1, 0);
                }
                else
                {
                    for (int k = 0; k < 4; k ++)
                        if (a[i][j] >> k & 1)
                            Addedge(idx[i][j][4], idx[i][j][k], 1, 0);
                        else
                            Addedge(idx[i][j][k ^ 1], idx[i][j][k], 1, 1), Addedge(idx[i][j][k ^ 2], idx[i][j][k], 1, 2), Addedge(idx[i][j][k ^ 3], idx[i][j][k], 1, 1);
                }
            }
            else
            {
                Addedge(idx[i][j][4], T, __builtin_popcount(a[i][j]), 0);
                if (a[i][j] == 1 || a[i][j] == 2 || a[i][j] == 4 || a[i][j] == 8)
                {
                    for (int k = 0; k < 4; k ++)
                        if (a[i][j] >> k & 1)
                            Addedge(idx[i][j][k], idx[i][j][4], 1, 0), Addedge(idx[i][j][k ^ 1], idx[i][j][k], 1, 1), Addedge(idx[i][j][k ^ 2], idx[i][j][k], 1, 2), Addedge(idx[i][j][k ^ 3], idx[i][j][k], 1, 1);
                }
                else if (a[i][j] == 3 || a[i][j] == 6 || a[i][j] == 12 || a[i][j] == 9)
                {
                    for (int k = 0; k < 4; k ++)
                        if (a[i][j] >> k & 1)
                            Addedge(idx[i][j][k], idx[i][j][4], 1, 0), Addedge(idx[i][j][k ^ 2], idx[i][j][k], 1, 1);
                }
                else if (a[i][j] == 5 || a[i][j] == 10 || a[i][j] == 15)
                {
                    for (int k = 0; k < 4; k ++)
                        if (a[i][j] >> k & 1)
                            Addedge(idx[i][j][k], idx[i][j][4], 1, 0);
                }
                else
                {
                    for (int k = 0; k < 4; k ++)
                        if (a[i][j] >> k & 1)
                            Addedge(idx[i][j][k], idx[i][j][4], 1, 0);
                        else
                            Addedge(idx[i][j][k], idx[i][j][k ^ 1], 1, 1), Addedge(idx[i][j][k], idx[i][j][k ^ 2], 1, 2), Addedge(idx[i][j][k], idx[i][j][k ^ 3], 1, 1);
                }
            }
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            if (i + j & 1)
            {
                if (i)
                    Addedge(idx[i][j][0], idx[i - 1][j][2], 1, 0);
                if (j < m)
                    Addedge(idx[i][j][1], idx[i][j + 1][3], 1, 0);
                if (i < n)
                    Addedge(idx[i][j][2], idx[i + 1][j][0], 1, 0);
                if (j)
                    Addedge(idx[i][j][3], idx[i][j - 1][1], 1, 0);
            }
    pii ret = Solve();
    if (ret.xx ^ l)
        return puts("-1"), 0;
    return printf("%d\n", ret.yy), 0;
}

helloworld

根号分治,大于根号的暴力跳,小于根号的用数据结构维护根号棵树, 第 i 棵树的父亲实际上是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 LL Read()
{
    LL x = 0; int 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;
const int MAXM = 240;
const int M = 233;
const int B = 20;

int n, m, tim, dep[MAXN], par[MAXN], g[16][MAXN], f[MAXM][MAXN], dfn[MAXM][MAXN], siz[MAXM][MAXN], anc_big[MAXM][MAXN], anc_small[MAXM][MAXN];
vector <int> dfs_seq, adj[MAXN], adv[MAXM][MAXN];
LL a[MAXN], bit[MAXM][MAXN];

inline void DFS(int x)
{
    dfs_seq.pb(x), anc_small[0][x] = anc_big[0][x] = x, g[0][x] = par[x];
    for (int i = 1; i <= M; i ++)
        anc_small[i][x] = par[anc_small[i - 1][x]];
    for (int i = 1; i <= M; i ++)
        anc_big[i][x] = anc_small[M][anc_big[i - 1][x]];
    for (int i = 1; i <= 15; i ++)
        g[i][x] = g[i - 1][g[i - 1][x]];
    for (auto y : adj[x])
        if (y ^ par[x])
            par[y] = x, dep[y] = dep[x] + 1, DFS(y);
}

inline int Anc(int x, int k)
{
    return anc_big[k / M][anc_small[k % M][x]];
}

inline int LCA(int x, int y)
{
    if (dep[x] > dep[y])
        x = Anc(x, dep[x] - dep[y]);
    else if (dep[x] < dep[y])
        y = Anc(y, dep[y] - dep[x]);
    if (x == y)
        return x;
    for (int i = 15; ~i; i --)
        if (g[i][x] ^ g[i][y])
            x = g[i][x], y = g[i][y];
    return g[0][x];
}

inline void DFS(int x, int b)
{
    dfn[b][x] = ++ tim, siz[b][x] = 1;
    for (auto y : adv[b][x])
        DFS(y, b), siz[b][x] += siz[b][y];
}

inline int Fnd(int x, int b)
{
    while (x ^ f[b][x])
        x = f[b][x] = f[b][f[b][x]];
    return x;
}

inline void Modify(int x, int b, LL v)
{
    for (; x <= n; x += x & -x)
        bit[b][x] += v;
}

inline LL Query(int x, int b)
{
    LL r = 0;
    for (; x; x -= x & -x)
        r += bit[b][x];
    return r;
}

inline void Modify(int x, LL v)
{
    for (int i = 1; i <= B; i ++)
        Modify(dfn[i][x], i, v), Modify(dfn[i][x] + siz[i][x], i, -v);
}

inline void Modify(int x)
{
    if (a[x] == 1)
        return ;
    Modify(x, (LL)sqrt(a[x]) - a[x]), a[x] = sqrt(a[x]);
    if (a[x] == 1)
        for (int i = 1; i <= B; i ++)
            f[i][x] = Fnd(anc_small[i][x], i);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1; i <= n; i ++)
        a[i] = Read();
    for (int i = 1, x, y; i < n; i ++)
        x = Read(), y = Read(), adj[x].pb(y), adj[y].pb(x);
    dep[1] = 1, DFS(1);
    for (int j = 1; j <= B; j ++)
        for (int i = 1; i <= n; i ++)
            if (anc_small[j][i])
                adv[j][anc_small[j][i]].pb(i);
    for (int j = 1; j <= B; tim = 0, j ++)
        for (int i = 0; i < n; i ++)
            if (!dfn[j][dfs_seq[i]])
                DFS(dfs_seq[i], j);
    for (int j = 1; j <= B; j ++)
        for (int i = 1; i <= n; i ++)
            f[j][i] = i;
    for (int i = 1; i <= n; i ++)
        Modify(i, a[i]);
    for (int i = 1; i <= n; i ++)
        if (a[i] == 1)
            for (int j = 1; j <= B; j ++)
                f[j][Fnd(i, j)] = Fnd(anc_small[j][i], j);
    m = Read();
    while (m --)
    {
        int opt = Read(), s = Read(), t = Read(), k = Read(), p = LCA(s, t), len = dep[s] + dep[t] - (dep[p] << 1);
        if (k > B)
        {
            if (opt)
            {
                int x = s, y = s;
                LL ret = 0;
                for (; dep[x] >= dep[p]; y = x, x = Anc(x, k))
                    ret += a[x];
                if (y ^ t)
                    for (ret += a[t], x = Anc(t, (len - 1) % k + 1); dep[x] > dep[p]; x = Anc(x, k))
                        ret += a[x];
                printf("%lld\n", ret);
            }
            else
            {
                int x = s, y = s;
                for (; dep[x] >= dep[p]; y = x, x = Anc(x, k))
                    Modify(x);
                if (y ^ t)
                    for (Modify(t), x = Anc(t, (len - 1) % k + 1); dep[x] > dep[p]; x = Anc(x, k))
                        Modify(x);
            }
        }
        else
        {
            if (opt)
            {
                LL ret = 0;
                int x = s, y = par[p];
                if (dep[x] % k > dep[y] % k)
                    y = anc_small[k - dep[x] % k + dep[y] % k][y];
                else
                    y = anc_small[dep[y] % k - dep[x] % k][y];
                ret = Query(dfn[k][x], k) - Query(dfn[k][y], k);
                if (((dep[x] - dep[p]) % k) || (t ^ p))
                {
                    ret += a[t], t = Anc(t, (len - 1) % k + 1);
                    x = t, y = p;
                    if (dep[x] % k > dep[y] % k)
                        y = anc_small[k - dep[x] % k + dep[y] % k][y];
                    else
                        y = anc_small[dep[y] % k - dep[x] % k][y];
                    ret += Query(dfn[k][x], k) - Query(dfn[k][y], k);
                }
                printf("%lld\n", ret);
            }
            else
            {
                int x = s;
                for (x = Fnd(x, k); dep[x] >= dep[p]; x = Fnd(anc_small[k][x], k))
                    Modify(x);
                if (((dep[s] - dep[p]) % k) || (t ^ p))
                    for (Modify(t), x = Fnd(Anc(t, (len - 1) % k + 1), k); dep[x] > dep[p]; x = Fnd(anc_small[k][x], k))
                        Modify(x);
            }
        }
    }
    return 0;
}

Day 2

metro

首先每个点可以向上向下,这样我们可以得到一个 O(2n×poly(n)) 的算法。

将点按照左端点排序,不难发现这个位置对之后的影响只跟右端点的决策有关,所以变成了 O(2n/2×poly(n))

加上最优性剪枝即可。

#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;
}

int n, m, ans, a[50], l[25], r[25], p[25], q[25];

inline int F(int x, int u, int v)
{
    int ret = 0;
    for (int i = 0; i < x; i ++)
        if (l[x] < r[i])
            if (r[x] < r[i])
                ret += u ^ v;
            else if (p[i] == q[i])
                ret += u == p[i];
            else
                ret += u == q[i];
    return ret;
}   

inline void DFS(int x, int cur)
{
    if (cur >= ans)
        return ;
    if (x == m)
        return (void)(ans = cur);
    int u, v;
    u = F(x, 0, 0), v = F(x, 1, 0);
    if (u < v)
        p[x] = 0, q[x] = 0, DFS(x + 1, cur + u);
    else
        p[x] = 1, q[x] = 0, DFS(x + 1, cur + v);
    u = F(x, 0, 1), v = F(x, 1, 1);
    if (u < v)
        p[x] = 0, q[x] = 1, DFS(x + 1, cur + u);
    else
        p[x] = 1, q[x] = 1, DFS(x + 1, cur + v);
}

inline void Solve()
{
    n = Read(), m = 0, ans = 1 << 30;
    for (int i = 1; i <= n; i ++)
        a[i] = Read();
    for (int i = 1; i <= n; i ++)
        for (int j = i + 1; j <= n; j ++)
            if (a[i] == a[j])
                l[m] = i, r[m] = j, m ++;
    DFS(0, 0);
    printf("%d\n", ans);
}

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

binary

预处理子树内和子树外的最小字典序遍历,然后贪心。

#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;

const int MAXN = 1000005;

char B[1 << 23], *S = B, *T = B, C[1 << 23], *A = C;

inline char GetChar()
{
    if (S == T)
        T = (S = B) + fread(B, 1, 1 << 23, stdin);
    return S == T ? 0 : *S ++;
}

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;
}

inline int Write(int x)
{
    static int c[20], t;
    if (!x)
        *A ++ = '0';
    else
    {
        if (x < 0)
            *A ++ = '-', x = -x;
        for (t = 0; x; c[t ++] = x % 10 + '0', x /= 10);
        for (; t --; *A ++ = c[t]);
    }
}

int n, m, k[MAXN], f[MAXN], g[MAXN], ans[MAXN], par[MAXN], chd[MAXN][2], a[MAXN][4];
bool vis[MAXN];

inline void DFS_F(int x)
{
    for (int i = 1; i <= k[x]; i ++)
        if (a[x][i] ^ par[x])
        {
            par[a[x][i]] = x, DFS_F(a[x][i]);
            if (!chd[x][0])
                chd[x][0] = a[x][i];
            else
                chd[x][1] = a[x][i];
        }
    if (!chd[x][0])
        f[x] = x;
    else if (chd[x][1])
        f[x] = min(f[chd[x][0]], f[chd[x][1]]);
    else
        f[x] = min(f[chd[x][0]], x);
}

inline void DFS_G(int x)
{
    if (chd[x][1])
        g[chd[x][0]] = min(g[x], f[chd[x][1]]), g[chd[x][1]] = min(g[x], f[chd[x][0]]), DFS_G(chd[x][0]), DFS_G(chd[x][1]);
    else if (chd[x][0])
        g[chd[x][0]] = min(x, g[x]), DFS_G(chd[x][0]);
}

inline void Solve(int x, bool t)
{
    vis[x] = true;
    if (t)
    {
        if (!chd[x][0])
            ans[++ m] = x;
        else if (chd[x][1])
        {
            if (f[chd[x][0]] < f[chd[x][1]])
                Solve(chd[x][0], 1), ans[++ m] = x, Solve(chd[x][1], 1);
            else
                Solve(chd[x][1], 1), ans[++ m] = x, Solve(chd[x][0], 1);
        }
        else
        {
            if (x < f[chd[x][0]])
                ans[++ m] = x, Solve(chd[x][0], 1);
            else
                Solve(chd[x][0], 1), ans[++ m] = x;
        }
    }
    else
    {
        ans[++ m] = x;
        int p[4], v[4], c = 0;
        for (int i = 1; i <= k[x]; i ++)
            if (!vis[a[x][i]])
                p[++ c] = a[x][i], v[c] = a[x][i] == par[x] ? g[x] : f[a[x][i]];
        if (!c)
            return ;
        else if (c == 1)
            Solve(p[1], v[1] <= p[1]);
        else if (v[1] < v[2])
            Solve(p[1], 1), Solve(p[2], 0);
        else
            Solve(p[2], 1), Solve(p[1], 0);
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1, j; i <= n; i ++)
        for (j = 1, k[i] = Read(); j <= k[i]; j ++)
            a[i][j] = Read();
    int p = 0;
    for (int i = n; i; i --)
        if (k[i] <= 2)
            p = i;
    DFS_F(p), g[p] = n + 1, DFS_G(p), Solve(p, 0);
    for (int i = 1; i <= n; i ++)
        Write(ans[i]), *A ++ = i == n ? '\n' : ' ';
    fwrite(C, 1, A - C, stdout);
    return 0;
}

patron

首先状态只有 (m+kk) 种,矩乘即可。

预处理 2 的次幂的矩阵,每次询问用向量乘矩阵。

#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 LL Read()
{
    LL x = 0; int 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 = 170;
const int mod = 998244353;

int T, m, k, tot, cur[4], ret[MAXN], tmp[MAXN], a[MAXN][4];
map <int, int> idx;

struct Matrix
{
    int a[MAXN][MAXN];

    Matrix() { mset(a, 0); }

    Matrix operator * (const Matrix &b) const
    {
        Matrix c;
        for (int k = 0; k <= tot; k ++)
            for (int i = 0; i <= tot; i ++)
                for (int j = 0; j <= tot; j ++)
                    c.a[i][k] = (1LL * a[i][j] * b.a[j][k] + c.a[i][k]) % mod;
        return c;
    }
} mat[60];

inline int Qow(int x, int y)
{
    int r = 1;
    for (; y; y >>= 1, x = 1LL * x * x % mod)
        if (y & 1)
            r = 1LL * r * x % mod;
    return r;
}

inline void DFS(int x, int y)
{
    if (!x)
    {
        int val = 0;
        cur[x] = y, tot ++;
        for (int i = 0; i <= m; i ++)
            a[tot][i] = cur[i], val = val * 9 + cur[i];
        idx[val] = tot;
        return ;
    }
    for (cur[x] = 0; cur[x] <= y; cur[x] ++)
        DFS(x - 1, y - cur[x]);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    T = Read(), m = Read(), k = Read();
    DFS(m, k), mat[0].a[0][0] = 1;
    for (int i = 1; i <= tot; i ++)
    {
        int sum = Qow(k - a[i][0] + 1, mod - 2);
        mat[0].a[i][i] = mat[0].a[i][0] = sum;
        for (int j = 1; j <= m; j ++)
            if (a[i][j])
            {
                mcpy(cur, a[i]);
                cur[j] --, cur[j - 1] ++;
                if ((j ^ 1) && (cur[0]))
                    cur[0] --, cur[m] ++;
                int val = 0;
                for (int j = 0; j <= m; j ++)
                    val = val * 9 + cur[j];
                val = idx[val];
                mat[0].a[i][val] = (1LL * a[i][j] * sum + mat[0].a[i][val]) % mod;
            }
    }
    for (int i = 1; i < 60; i ++)
        mat[i] = mat[i - 1] * mat[i - 1];
    while (T --)
    {
        LL n = Read();
        for (int i = 0; i <= tot; i ++)
            ret[i] = 0;
        int val = 0;
        cur[0] = k - 1;
        for (int i = 1; i <= m; i ++)
            cur[i] = i == m;
        for (int i = 0; i <= m; i ++)
            val = val * 9 + cur[i];
        ret[idx[val]] = 1;
        for (int k = 59; ~k; k --)
            if (n >> k & 1)
            {
                for (int i = 0; i <= tot; i ++)
                    tmp[i] = 0;
                for (int i = 0; i <= tot; i ++)
                    for (int j = 0; j <= tot; j ++)
                        tmp[j] = (1LL * ret[i] * mat[k].a[i][j] + tmp[j]) % mod;
                for (int i = 0; i <= tot; i ++)
                    ret[i] = tmp[i];
            }
        printf("%d\n", ret[0]);
    }
}

Day 3

dsa

每次操作暴力维护DP值,瓶颈在于约数的约数个数记为 f ,打表发现前QC大的 f 值并不大。

#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 = 1000005;
const int MAXM = 25;

int n, m, q, l, r, ans[MAXM], a[MAXN], f[MAXN], plc[MAXN], g[MAXN][MAXM];
vector <int> fac[MAXN];

inline int Get(int x)
{
    for (int i = 20; i; i --)
        if (g[x][i])
            return i + 1;
    return 1;
}

inline void Add(int x, int v)
{
    for (auto i : fac[x])
        if (plc[i] && plc[i] < plc[x])
            g[i][f[x]] += v;
    ans[f[x]] += v;
}

inline void AddL(int x)
{
    l --, a[l] = x, plc[x] = l, f[x] = 0, mset(g[x], 0);
    for (int i = x; i <= m; i += x)
        if (plc[i])
            g[x][f[i]] ++;
    f[x] = Get(x), ans[f[x]] ++;
}

inline void AddR(int x)
{
    r ++, a[r] = x, plc[x] = r, f[x] = 1, Add(x, 1), mset(g[x], 0);
    for (auto i : fac[x])
        if (plc[i])
        {
            int d = Get(i);
            if (d ^ f[i])
                Add(i, -1), f[i] = d, Add(i, 1);
        }
}

inline void DelL()
{
    int x = a[l ++];
    plc[x] = 0, ans[f[x]] --, f[x] = 0;
}

inline void DelR()
{
    int x = a[r --];
    Add(x, -1), plc[x] = 0, f[x] = 0;
    for (auto i : fac[x])
        if (plc[i])
        {
            int d = Get(i);
            if (d ^ f[i])
                Add(i, -1), f[i] = d, Add(i, 1);
        }
}

inline void Print()
{
    for (int i = 20; i; i --)
        if (ans[i])
            return (void)printf("%d %d\n", i, ans[i]);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read(), q = Read();
    for (int i = m; i; i --)
        for (int j = i; j <= m; j += i)
            fac[j].pb(i);
    l = q + 1, r = q;
    for (int i = 1; i <= n; i ++)
        AddR(Read());
    Print();
    while (q --)
    {
        int opt = Read();
        if (!opt)
            AddL(Read());
        else if (opt == 1)
            AddR(Read());
        else if (opt == 2)
            DelL();
        else
            DelR();
        Print();
    }
    return 0;
}

frogs

把转移写出来,然后可以手推,下面几层是surreal number

一些特殊情况是 ={0|0},={0|},={|0} ,具体可以参见题解。

计数部分就是组合数前缀和。

#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 = 1000005;
const int mod = 998244353;

int sum[MAXN], fac[MAXN], inv[MAXN], bin[MAXN];

inline int C(int x, int y)
{
    if (x < 0 || y < 0 || x < y)
        return 0;
    return 1LL * fac[x] * inv[y] % mod * inv[x - y] % mod;
}

inline void Solve()
{
    int n = Read(), u = 0, d = 0, s = 0, x = 0, y = 0, z = 0, v = 0, w = 0;
    for (int i = 1; i <= n; i ++)
    {
        string str;
        cin >> str;
        if (str == "LL_RR" || str == "LRL_R" || str == "L_RLR")
            s += Read();
        else if (str == "L_LRR")
            u += Read();
        else if (str == "LLR_R")
            d += Read();
        else if (str == "RL_LR")
            v += Read();
        else if (str == "LR_RL")
            w += Read();
        else if (str == "LRRL_" || str == "RRL_L" || str == "RLRL_")
            y += Read();
        else if (str == "_RLLR" || str == "R_RLL" || str == "_RLRL")
            z += Read();
        else
            x += Read();
    }
    int ansl = 0, ansr = 0, ansf = 0, anss = 0, zero = 0, a = v + w, b = y + z, k = (z << 1) + w, ways = 0;
    for (int i = 0; i <= a; i ++)
        sum[i] = C(a, i);
    for (int i = a - 1; ~i; i --)
        sum[i] = (sum[i] + sum[i + 1]) % mod;
    for (int i = 0; i <= b; i ++)
    {
        int ways = C(b, i), cur = k + 1 - (i << 1);
        if (cur > a)
            continue;
        else if (cur < 0)
            cur = 0;
        ansl = (1LL * ways * sum[cur] + ansl) % mod;
    }
    for (int i = 0; i <= a; i ++)
        sum[i] = C(a, i);
    for (int i = 1; i <= a; i ++)
        sum[i] = (sum[i] + sum[i - 1]) % mod;
    for (int i = 0; i <= b; i ++)
    {
        int ways = C(b, i), cur = k - 1 - (i << 1);
        if (cur < 0)
            break;
        else if (cur > a)
            cur = a;
        ansr = (1LL * ways * sum[cur] + ansr) % mod;
    }
    zero = (0LL + bin[a + b] - ansl - ansr + mod + mod) % mod * bin[x] % mod;
    ansl = 1LL * ansl * bin[x + u + d + s] % mod;
    ansr = 1LL * ansr * bin[x + u + d + s] % mod;
    ways = 0;
    for (int i = 0; i <= s; i += 2)
        ways = (ways + C(s, i)) % mod;
    ways = 1LL * ways * zero % mod;
    for (int i = 0; i <= d; i ++)
        sum[i] = C(d, i);
    for (int i = 1; i <= d; i ++)
        sum[i] = (sum[i] + sum[i - 1]) % mod;
    for (int i = 1; i <= u; i ++)
        ansl = (1LL * C(u, i) * sum[min(i - 1, d)] % mod * ways + ansl) % mod;
    for (int i = 0; i <= d; i ++)
        sum[i] = C(d, i);
    for (int i = d - 1; ~i; i --)
        sum[i] = (sum[i] + sum[i + 1]) % mod;
    for (int i = 0; i <= u && i < d; i ++)
        ansr = (1LL * C(u, i) * sum[i + 1] % mod * ways + ansr) % mod;
    for (int i = 0; i <= min(u, d); i ++)
        anss = (1LL * C(u, i) * C(d, i) % mod * ways + anss) % mod;
    ways = 0;
    for (int i = 1; i <= s; i += 2)
        ways = (ways + C(s, i)) % mod;
    ways = 1LL * ways * zero % mod;
    for (int i = 0; i <= d; i ++)
        sum[i] = C(d, i);
    for (int i = 1; i <= d; i ++)
        sum[i] = (sum[i] + sum[i - 1]) % mod;
    for (int i = 2; i <= u; i ++)
        ansl = (1LL * C(u, i) * sum[min(i - 2, d)] % mod * ways + ansl) % mod;
    for (int i = 0; i <= d; i ++)
        sum[i] = C(d, i);
    for (int i = d - 1; ~i; i --)
        sum[i] = (sum[i] + sum[i + 1]) % mod;
    for (int i = 0; i <= u && i + 1 < d; i ++)
        ansr = (1LL * C(u, i) * sum[i + 2] % mod * ways + ansr) % mod;
    for (int i = 0; i <= u; i ++)
        ansf = (1LL * C(u, i) * (0LL + C(d, i - 1) + C(d, i) + C(d, i + 1)) % mod * ways + ansf) % mod;
    printf("%d %d %d %d\n", ansl, ansr, ansf, anss);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    Read(), fac[0] = fac[1] = inv[0] = inv[1] = bin[0] = 1;
    int N = 1000000;
    for (int i = 2; i <= N; i ++)
        fac[i] = 1LL * fac[i - 1] * i % mod, inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
    for (int i = 1; i <= N; i ++)
        inv[i] = 1LL * inv[i - 1] * inv[i] % mod, bin[i] = (bin[i - 1] << 1) % mod;
    for (int T = Read(); T; T --)
        Solve();
    return 0;
}

hafen

打表发现存在反例可以表示成 i,j,j 的形式,对于小范围可以直接暴力。

对于大范围的数据,还可以发现可以表示成 x=p×q 的形式,然后 p 大约是n13 q 大约是n12,且 p,q 都是质数。

#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;
}

inline bool IsPrime(int x)
{
    if (x < 2)
        return false;
    for (int i = 2; i * i <= x; i ++)
        if (x % i == 0)
            return false;
    return true;
}

inline void Solve()
{
    int n = Read();
    if (n <= 200)
    {
        for (int i = 2; i < n; i ++)
            for (int j = i; j < n; j ++)
            {
                LL x = i * j * j;
                int cnt = 0;
                for (int k = n - 1; k > 1; k --)
                    while (x % k == 0)
                        x /= k, cnt ++;
                if (cnt > 3)
                {
                    printf("3 %d %d %d\n", i, j, j);
                    goto OK;
                }
            }
        puts("-1");
        OK:;
    }
    else
    {
        int x = ceil(sqrt(n)), y = pow(n - 1, 1.0 / 3);
        for (; !IsPrime(x); x ++);
        for (; !IsPrime(y); y --);
        printf("3 %d %d %d\n", x * y, x * y, x * y);
    }
}

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

Day 4

game

每次暴力找循环节,那么每次线的长度相当于对循环节取模,所以至少除以二。

预处理极角排序,每次暴力往下找,因为转了一圈所以均摊下来是线性的。

#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;
const double PI = acos(-1);
const double eps = 1e-8;

int n, m, tim, vis[MAXN][MAXN];
double dis[MAXN][MAXN];

inline int Sgn(double x) { return fabs(x) < eps ? 0 : x > 0 ? 1 : -1; }
inline int Cmp(double x, double y) { return Sgn(x - y); }

struct Point
{
    double x, y;
    Point(double x = 0, double y = 0):x(x), y(y) {}
    Point operator + (const Point &b) const { return Point(x + b.x, y + b.y); }
    Point operator - (const Point &b) const { return Point(x - b.x, y - b.y); }
    Point operator * (const double &b) const { return Point(x * b, y * b); }
    Point operator / (const double &b) const { return Point(x / b, y / b); }
    double operator * (const Point &b) const { return x * b.y - y * b.x; }
    inline double Len() { return sqrt(x * x + y * y); }
    inline double Ang() { return atan2(y, x); }
    inline Point Nor() { return (*this) / Len(); }
    inline bool Bel() { return Sgn(y) > 0 || (!Sgn(y) && Sgn(x) < 0); }
} p[MAXN], tmp[MAXN];

struct Node
{
    int cnt, a[MAXN], per[MAXN], pos[MAXN];
    double all, d[MAXN], val[MAXN];

    inline void Init(int x)
    {
        int m = 0, lst = 0;
        for (int i = 1; i <= n; i ++)
            if (i ^ x)
                tmp[i] = p[i] - p[x], tmp[i + n] = p[x] - p[i], d[i] = d[i + n] = dis[i][x], per[++ m] = i, per[++ m] = i + n;
        sort(per + 1, per + m + 1, [&](const int &x, const int &y)
        {
            if (tmp[x].Bel() ^ tmp[y].Bel())
                return tmp[x].Bel() > tmp[y].Bel();
            double crs = tmp[x] * tmp[y];
            return Sgn(crs) ? Sgn(crs) < 0 : d[x] > d[y];
        });
        cnt = 0, all = 1e9;
        for (int i = 1; i <= m; i ++)
            if (per[i] <= n)
            {
                a[++ cnt] = per[i], all = min(all, val[cnt] = d[per[i]]);
                for (int j = lst + 1; j < i; j ++)
                    pos[per[j] - n] = cnt;
                lst = i;
            }
        for (int i = lst + 1; i <= m; i ++)
            pos[per[i] - n] = 1;
    }

    inline int FindNext(int x, double len)
    {
        if (Cmp(all, len) > 0)
            return 0;
        for (x = pos[x]; Cmp(val[x], len) > 0; x = x % cnt + 1);
        return a[x];
    }

} a[MAXN];

inline double Dis(Point x, Point y)
{
    return (x - y).Len();
}

inline double Turn(Point x, Point y, Point z)
{
    double ang = (y - x).Ang() - (z - x).Ang();
    if (Sgn(ang) < 0)
        ang += PI * 2;
    else if (Cmp(ang, PI * 2) > 0)
        ang -= PI * 2;
    return ang;
}

inline int FindNext(Point s, Point t, int ban)
{
    double ang = 1e9, dis = 1e9, len = Dis(s, t), cur_ang, cur_dis;
    int pos = 0;
    for (int i = 1; i <= n; i ++)
        if ((i ^ ban) && Cmp(len, cur_dis = Dis(s, p[i])) >= 0 && (Cmp(cur_ang = Turn(s, t, p[i]), ang) < 0 || (!Cmp(cur_ang, ang) && cur_dis > dis)))
            pos = i, ang = cur_ang, dis = cur_dis;
    return pos;
}

inline int Work()
{
    int pre, cur, nxt, ret = 2;
    Point s, t;
    double len;
    s.x = Read(), s.y = Read(), t.x = Read(), t.y = Read(), len = Read(), t = s + (t - s).Nor() * len;
    if (!(cur = FindNext(s, t, 0)))
        return 1;
    len -= Dis(s, p[cur]), t = p[cur] + (p[cur] - s).Nor() * len, s = p[pre = cur];
    if (!(cur = FindNext(s, t, pre)))
        return 2;
    len -= Dis(s, p[cur]);
    while (true)
    {
        int m = 1, pos = 1, cnt = 0, times;
        double pre_len = len, cir = 0;
        vector <int> vec;
        vec.pb(pre), vec.pb(cur), tim ++;
        while (true)
        {
            vec.pb(nxt = a[cur].FindNext(pre, len)), m ++;
            if (!nxt)
                return ret + vec.size() - 2;
            len -= dis[cur][nxt];
            if (vis[pre][cur] == tim)
                break;
            vis[pre][cur] = tim, pre = cur, cur = nxt;
        }
        for (len = pre_len; (vec[pos - 1] ^ pre) || (vec[pos] ^ cur); pos ++)
            ret ++, len -= dis[vec[pos]][vec[pos + 1]];
        for (; pos < m - 1; pos ++)
            cnt ++, cir += dis[vec[pos]][vec[pos + 1]];
        times = len / cir, ret += times * cnt, len -= times * cir, pre = vec[m - 2], cur = vec[m - 1];
    }
}

inline void Solve()
{
    n = Read(), m = Read();
    for (int i = 1; i <= n; i ++)
        p[i].x = Read(), p[i].y = Read();
    for (int i = 1; i <= n; i ++)
        for (int j = i; j <= n; j ++)
            dis[i][j] = dis[j][i] = Dis(p[i], p[j]);
    for (int i = 1; i <= n; i ++)
        a[i].Init(i);
    for (int i = 1; i <= m; i ++)
        printf("%d\n", Work());
}

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

core

首先判断深度的奇偶性。

注意到子树内的点可以相互抵消,而如果某个子树过大,那么可以先进去再出来,让那个子树内的点互相抵消。

做一遍树形 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 = 100005;

int n, sub, f[MAXN], par[MAXN], dep[MAXN], siz[MAXN], ans[MAXN];
pii pre[MAXN], suf[MAXN];
vector <int> adj[MAXN];

inline void DFS(int x)
{
    siz[x] = 1;
    if (x ^ 1)
        adj[x].erase(find(adj[x].begin(), adj[x].end(), par[x]));
    for (auto y : adj[x])
        par[y] = x, dep[y] = dep[x] + 1, DFS(y), siz[x] += siz[y];
}

inline void DP(int x)
{
    pii cur = mp(0, 0);
    int tot = 0;
    for (auto y : adj[x])
        DP(y), cur = max(cur, mp(siz[y], y)), tot += siz[y];
    f[x] = min(max(cur.xx - (tot - cur.xx), 0), max(f[cur.yy] + cur.xx + 1 - tot, 0));
}

inline void DFS(int x, int tot, pii cur)
{
    int val = cur.xx, pos = cur.yy;
    for (int i = 0; i < adj[x].size(); i ++)
        tot += siz[adj[x][i]];
    for (int i = 0; i < adj[x].size(); i ++)
        pre[adj[x][i]] = max(i ? pre[adj[x][i - 1]] : cur, mp(siz[adj[x][i]], adj[x][i]));
    for (int i = adj[x].size() - 1; ~i; i --)
        suf[adj[x][i]] = max(i + 1 < adj[x].size() ? suf[adj[x][i + 1]] : cur, mp(siz[adj[x][i]], adj[x][i]));
    if (!adj[x].empty())
        val = suf[adj[x][0]].xx, pos = suf[adj[x][0]].yy;
    if (((dep[x] ^ n) & 1) && (val <= tot - val || f[pos] <= tot - val - 1))
        ans[x] = 1;
    else
        ans[x] = 0;
    for (int i = 0; i < adj[x].size(); i ++)
        DFS(adj[x][i], tot - siz[adj[x][i]], max(i ? pre[adj[x][i - 1]] : cur, i + 1 < adj[x].size() ? suf[adj[x][i + 1]] : cur));
}

inline void Solve()
{
    n = Read();
    for (int i = 1; i <= n; i ++)
        adj[i].clear();
    for (int i = 1, x, y; i < n; i ++)
        x = Read(), y = Read(), adj[x].pb(y), adj[y].pb(x);
    DFS(1), DP(1), DFS(1, 0, mp(0, 0));
    if (sub == 3)
        putchar(ans[1] + '0');
    else
        for (int i = 1; i <= n; i ++)
            putchar(ans[i] + '0');
    putchar(10);
}

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

rmq

首先离散化,接下来就知道每个部分的最大值了。

特判掉不合法的情况,接下来从小到大处理,可以转化为:有若干个区间,区间内至少有一个最大值,问方案数。

fi 表示最后一个最大值在 i <script type="math/tex" id="MathJax-Element-44">i</script>这段区间的方案数,暴力转移。

#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;
const int mod = 998244353;

struct Node
{
    int l, r, a;

    bool operator < (const Node &b) const
    {
        return a < b.a;
    }
} a[MAXN];

int n, m, c, top, ret, val[MAXN], l[MAXN], f[MAXN];
bool vis[MAXN];

inline int Qow(int x, int y)
{
    int r = 1;
    for (; y; y >>= 1, x = 1LL * x * x % mod)
        if (y & 1)
            r = 1LL * r * x % mod;
    return r;
}

inline void Solve(int L, int R)
{
    vector <int> seq, sum;
    for (int i = L; i <= R; i ++)
        for (int j = a[i].l; j < a[i].r; j ++)
            if (!vis[j])
                vis[j] = 1, seq.pb(j);
    sort(seq.begin(), seq.end());
    int n = seq.size();
    for (int i = 0; i < n; i ++)
        sum.pb(l[seq[i] + 1] - l[seq[i]] + (i ? sum[i - 1] : 0));
    for (int i = L; i <= R; i ++)
        a[i].l = lower_bound(seq.begin(), seq.end(), a[i].l) - seq.begin(), a[i].r = lower_bound(seq.begin(), seq.end(), a[i].r) - seq.begin() - 1;
    f[0] = 1;
    for (int i = 0; i < n; i ++)
    {
        int ways = (Qow(a[L].a, l[seq[i] + 1] - l[seq[i]]) - Qow(a[L].a - 1, l[seq[i] + 1] - l[seq[i]]) + mod) % mod, p = 0;
        f[i + 1] = 0;
        for (int j = L; j <= R; j ++)
            if (a[j].r < i)
                p = max(p, a[j].l + 1);
        for (int j = p; j <= i; j ++)
            f[i + 1] = (1LL * f[j] * Qow(a[L].a - 1, (i ? sum[i - 1] : 0) - (j ? sum[j - 1] : 0)) + f[i + 1]) % mod;
        f[i + 1] = 1LL * f[i + 1] * ways % mod;
    }
    int ans = 0, p = 0;
    for (int i = L; i <= R; i ++)
        p = max(p, a[i].l + 1);
    for (int i = p; i <= n; i ++)
        ans = (1LL * f[i] * Qow(a[L].a - 1, sum[n - 1] - sum[i - 1]) + ans) % mod;
    ret = 1LL * ret * ans % mod;
}

inline void Solve()
{
    n = Read(), m = Read(), c = Read(), top = 0, ret = 1;
    l[++ top] = 1, l[++ top] = n + 1;
    for (int i = 1; i <= m; i ++)
        l[++ top] = a[i].l = Read(), l[++ top] = a[i].r = Read() + 1, a[i].a = Read();
    sort(l + 1, l + top + 1), top = unique(l + 1, l + top + 1) - l - 1, sort(a + 1, a + m + 1);
    for (int i = 1; i < top; i ++)
        vis[i] = 0, val[i] = -1;
    for (int i = m; i; i --)
    {
        a[i].l = lower_bound(l + 1, l + top + 1, a[i].l) - l, a[i].r = lower_bound(l + 1, l + top + 1, a[i].r) - l;
        for (int j = a[i].l; j < a[i].r; j ++)
            val[j] = a[i].a;
    }
    for (int i = 1; i <= m; i ++)
    {
        int v = 0;
        for (int j = a[i].l; j < a[i].r; j ++)
            v = max(v, val[j]);
        if (v ^ a[i].a)
            return (void)puts("0");
    }
    for (int i = 1, j = 1; i <= m; i = j)
    {
        while (j <= m && a[j].a == a[i].a)
            j ++;
        Solve(i, j - 1);
    }
    int cnt = 0;
    for (int i = 1; i < top; i ++)
        if (!vis[i])
            cnt += l[i + 1] - l[i];
    ret = 1LL * ret * Qow(c, cnt) % mod;
    printf("%d\n", ret);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值