zoukankan      html  css  js  c++  java
  • 「CometOJ」Contest #11

    Link

    Aeon

    显然字典序最大就是把最小的字母放在最后

    Business

    [动态规划]

    简单dp

    dp[i][j]dp[i][j]表示到第ii天,当前有jj块钱,最后返还的钱最多为多少

    完全背包转移

    Celebration

    Description

    有一个 ,求把它分成三段,使得每一段内无重复元素,且三段长度可以作为某个三角形的三边的方案数。

    一个拆分方案可以看作一个三元组 (a,b,c)(a,b,c),其中 0<a<b<cn0lt alt b lt c le n,表示在第 a,b,ca,b,c个位置之前断开。两个拆分不同当且仅当其对应的三元组不同。

    n2×106nle 2times10^6

    Solution

    [计数] [树状数组]

    定义长度不超过 n12frac{n-1}{2} ,且不含重复颜色的段为合法的段。记 prexpre_x 为以 为右端点的合法段最远的左端点,nxtxnxt_x 为以 xx 为左端点的合法段最远的右端点。

    先枚举题目中的aa,那么b(a,nxta+1]bin(a, nxt_a + 1]。在确定了a,ba, b的位置后,合法的cc位于(b,nxtb+1](b, nxt_b + 1][prea,n][pre_a, n]的交集中

    注意,这里的preapre_a必须是大于aa的,即绕了一圈绕到右边去。否则一定不合法

    可以用树状数组维护:

    从左往右枚举aa,把合法的bb对应的(b,nxtb+1](b, nxt_b + 1]这段区间在树状数组中+1;查询就直接查[prea,n][pre_a, n]的区间和;在离开aa的时候把(a,nxta+1](a, nxt_a + 1]区间-1

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126



    #define x first
    #define y second
    #define y1 Y1
    #define y2 Y2
    #define mp make_pair
    #define pb push_back
    #define DEBUG(x) cout << #x << " = " << x << endl;

    using namespace std;

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

    template <typename T> inline int (T &a, T b) { return a < b ? a = b, 1 : 0; }
    template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0; }
    template <typename T> inline T read ()
    {
    T sum = 0, fl = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0';
    return sum * fl;
    }

    inline void proc_status ()
    {
    ifstream t ("/proc/self/status");
    cerr << string (istreambuf_iterator <char> (t), istreambuf_iterator <char> ()) << endl;
    }

    const int Maxn = 2e6 + 10;

    int N;
    int A[Maxn];
    int vis[Maxn];
    int L[Maxn], R[Maxn];

    inline int fix (int x) { return ((x - 1) % N + N) % N + 1; }

    namespace BIT
    {
    struct bit
    {
    LL sum[Maxn];
    inline void add (int x, int val) { for (; x <= N; x += x & (-x)) sum[x] += val; }
    inline LL query (int x) { LL ans = 0; for (; x; x -= x & (-x)) ans += sum[x]; return ans; }
    } A, B;

    inline void update (int x, int y, int val)
    {
    if (x > y) return ;
    A.add (x, val * x), A.add (y + 1, -val * (y + 1));
    B.add (x, val), B.add (y + 1, -val);
    }

    inline LL query (int x) { return B.query (x) * (x + 1) - A.query (x); }

    inline LL query (int x, int y) { if (x > y) return 0; return query (y) - query (x - 1); }
    }

    inline void Init ()
    {
    int r = 0;
    for (int i = 1; i <= N; ++i)
    {
    while (r < N && !vis[A[r + 1]]) ++r, ++vis[A[r]];
    R[i] = min (r, i + (N - 1) / 2 - 1);
    if (vis[A[i]]) --vis[A[i]];
    }

    memset (vis, 0, sizeof vis);
    int l = 1;
    while (!vis[A[fix (l - 1)]]) l = fix (l - 1), ++vis[A[l]];
    L[1] = fix (max (l, N - (N - 1) / 2 + 1));

    for (int i = 2; i <= (N - 1) / 2; ++i)
    {
    while (vis[A[i - 1]]) --vis[A[l]], l = fix (l + 1);
    if (l < i) break;
    L[i] = max (l, fix ((i - 1 + N) - (N - 1) / 2 + 1));
    ++vis[A[i - 1]];
    }
    }

    inline void Solve ()
    {
    Init ();

    LL ans = 0;
    int p = 1;
    for (int i = 1; i <= N; ++i)
    {
    if (L[i] < i) break;
    while (p < N && p + 1 <= R[i] + 1)
    {
    ++p;
    BIT :: update (p + 1, R[p] + 1, 1);
    }
    ans += BIT :: query (L[i], N);
    BIT :: update ((i + 1) + 1, R[i + 1] + 1, -1);
    }

    cout << ans << endl;
    }

    inline void Input ()
    {
    N = read<int>();
    for (int i = 1; i <= N; ++i) A[i] = read<int>();
    }

    int main()
    {

    #ifdef hk_cnyali
    freopen("C.in", "r", stdin);
    freopen("C.out", "w", stdout);
    #endif

    Input ();
    Solve ();

    return 0;
    }

    Disaster

    [kruskal重构树]

    kruskal重构树模板题

    Effort

    Description

    mm种数据结构(可把数据结构想像成游戏中的种族),第 ii种有 aia_i个,每个可给敌人造成至少 11 次,至多 bib_i次伤害。有n n名敌人,每人承担至少一次伤害。求总情况数模 998244353998244353的值

    数据结构两两不同 (同种的任两个也不同),敌人两两不同。

    两种方案不同当且仅当某个数据结构造成的伤害不同,或某个敌人受到的伤害不同。

    n×m105,ai105,bi <998244353n times mle 10^5, a_ile 10^5, b_i < 998244353

    Solution

    [组合数学] [生成函数] [多项式] [NTT]

    注意到每个敌人的伤害是无序的,即这个敌人在被第几次攻击到都是一样的,而其他限制都是有序

    于是可以钦定攻击顺序和受到伤害的顺序。形象地理解就是先把所有数据结构按顺序摆一排,确定每数据结构攻击多少次,这样就确定出一个攻击序列。再在这个攻击序列上插n1n-1个板就是这个攻击序列方案数

    看上去这是由两个部分构成的(先确定攻击序列,再插板),但实际上可以同时算

    Fi(x)F_i(x)表示一个ii种数据结构插板方案的生成函数,它的kk次项系数表示插kk个板的方案数。那么[xk]Fiai(x)displaystyle [x^k]F_i^{a_i}(x)就是在第ii种里插kk个板的方案数了


    考虑如何求Fi(x)F_i(x)

    kk项系数其实就是

    (1k)+(2k)++(bik) binom{1}{k} + binom{2}{k} + cdots + binom{b_i}{k}

    枚举这个数据结构攻击tt

    那么就相当于有tt个空位(最后一个位置也是空位,但最后一个数据结构不是,需要单独考虑),插kk个板,就是(tk)binom{t}{k}

    发现除了k=0k=0之外,都是是杨辉三角一列的之和,就等于(bi+1k+1)binom{b_i + 1}{k + 1}

    因为bib_i很大,不能直接算,但是kk比较小,所以可以先O(1)O(1)计算出k=1k=1时的值,然后O(1)O(1)递推下一个kk的值


    由于只有n1n-1个板,所以多项式长度始终不超过n1n-1。直接做多项式快速幂即可,再把mm个多项式依次合起来

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    大专栏  「CometOJ」Contest #11ne">60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160



    #define x first
    #define y second
    #define y1 Y1
    #define y2 Y2
    #define mp make_pair
    #define pb push_back
    #define DEBUG(x) cout << #x << " = " << x << endl;

    using namespace std;

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

    template <typename T> inline int (T &a, T b) { return a < b ? a = b, 1 : 0; }
    template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0; }
    template <typename T> inline T read ()
    {
    T sum = 0, fl = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0';
    return sum * fl;
    }

    inline void proc_status ()
    {
    ifstream t ("/proc/self/status");
    cerr << string (istreambuf_iterator <char> (t), istreambuf_iterator <char> ()) << endl;
    }

    const int Maxn = 5e5 + 100;
    const int Mod = 998244353;

    namespace MATH
    {
    inline void Add (int &a, int b) { if ((a += b) >= Mod) a -= Mod; }

    inline int Pow (int a, int b)
    {
    int ans = 1;
    for (int i = b; i; i >>= 1, a = (LL) a * a % Mod) if (i & 1) ans = (LL) ans * a % Mod;
    return ans;
    }
    }

    using namespace MATH;

    int N, M;
    int A[Maxn], B[Maxn];

    namespace Poly
    {
    int rev[Maxn], n;
    int _Wn[2][Maxn];

    inline void init ()
    {
    n = 5e5;
    for (int mid = 1; mid <= n; mid <<= 1)
    {
    _Wn[0][mid] = Pow (3, (Mod - 1) / (mid << 1));
    _Wn[1][mid] = Pow (_Wn[0][mid], Mod - 2);
    }
    }

    inline void dft (int *A, int fg)
    {
    for (int i = 0; i < n; ++i) if (rev[i] < i) swap (A[rev[i]], A[i]);
    for (int mid = 1; mid < n; mid <<= 1)
    {
    int Wn = _Wn[fg][mid], len = mid << 1;
    for (int i = 0; i < n; i += len)
    for (int j = i, W = 1; j < i + mid; ++j, W = (LL) W * Wn % Mod)
    {
    int x = A[j], y = (LL) W * A[j + mid] % Mod;
    A[j] = (x + y) % Mod;
    A[j + mid] = (x - y + Mod) % Mod;
    }
    }
    if (fg) for (int i = 0, inv = Pow (n, Mod - 2); i < n; ++i) A[i] = (LL) A[i] * inv % Mod;
    }

    inline void mul (int *A, int *B, int *C, int N)
    {
    for (n = 1; n <= (N << 1); n <<= 1);
    for (int i = 0; i < n; ++i) rev[i] = (rev[i >> 1] >> 1) + ((i & 1) ? (n >> 1) : 0);

    static int F[Maxn], G[Maxn];
    for (int i = 0; i < n; ++i) F[i] = (i <= N) ? A[i] : 0;
    for (int i = 0; i < n; ++i) G[i] = (i <= N) ? B[i] : 0;

    dft (F, 0), dft (G, 0);
    for (int i = 0; i < n; ++i) F[i] = (LL) F[i] * G[i] % Mod;
    dft (F, 1);

    for (int i = 0; i <= (N << 1); ++i) C[i] = F[i];
    }
    }

    int F[Maxn], G[Maxn];
    int H[Maxn];

    inline void Solve ()
    {
    ++M;
    A[M] = 1, B[M] = B[M - 1] - 1;
    --A[M - 1];

    G[0] = 1;
    for (int i = 1; i <= M; ++i)
    {
    if (!A[i]) continue;
    #define n (B[i] + 1)
    #define m (j + 1)
    F[0] = (i == M) ? n : (n - 1);

    int res = (LL) n * (n - 1) / 2 % Mod;
    for (int j = 1; j <= N; ++j)
    {
    F[j] = res;
    res = (LL) res * (n - m) % Mod * Pow (m + 1, Mod - 2) % Mod;
    }

    for (int j = 0; j <= N; ++j) H[j] = 0;
    H[0] = 1;

    for (int j = A[i]; j; j >>= 1, Poly :: mul (F, F, F, N))
    if (j & 1)
    Poly :: mul (H, F, H, N);

    Poly :: mul (G, H, G, N);
    #undef n
    #undef m
    }

    cout << G[N] << endl;
    }

    inline void Input ()
    {
    N = read<int>() - 1, M = read<int>();
    for (int i = 1; i <= M; ++i) A[i] = read<int>(), B[i] = read<int>();
    }

    int main()
    {

    #ifdef hk_cnyali
    freopen("E.in", "r", stdin);
    freopen("E.out", "w", stdout);
    #endif

    Poly :: init ();
    Input ();
    Solve ();

    return 0;
    }

    Farewell

    Description

    有一张 nn个点 mm条边的图,第 ii条边 ui,viu_i,v_i13frac{1}{3}的概率从ui u_i指向 viv_i ,另 13frac{1}{3} 的概率从 viv_i 指向 uiu_i ,剩下 13frac{1}{3}的概率被删除。求这张图是有向无环图的概率

    n20nle 20

    Solution

    [FWT] [子集卷积] [动态规划] [状态压缩]

    FSF_S表示SS是DAG的方案数,ESE_S表示点集SS内部的边数,ES,TE_{S, T}表示SSTT之间的边数

    DAG计数显然枚举入度为00的点容斥

    FS=TS,T(1)T+1FST×2ET,ST F_S = sum_{Tsubseteq S, Tne emptyset} (-1)^{|T| + 1}F_{S - T}times 2^{E_{T, S - T}}

    2ET,ST 2^{E_{T, S - T}}是因为从STS-T T T的边只能断掉或指向TT

    又因为2ET,ST=2ESETEST 2^{E_{T, S - T}} = 2^{E_S - E_T - E_{S - T}},所以式子可以化为

    FS2ES=TS,T(1)T+12ET×FST2EST frac{F_S}{2^{E_S}} = sum_{Tsubseteq S, Tne emptyset} frac{(-1)^{|T| + 1}}{2^{E_{T}}} times frac{F_{S - T}}{2^{E_{S - T}}}

    子集卷积即可

    Code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126



    #define x first
    #define y second
    #define y1 Y1
    #define y2 Y2
    #define mp make_pair
    #define pb push_back
    #define DEBUG(x) cout << #x << " = " << x << endl;

    using namespace std;

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

    template <typename T> inline int (T &a, T b) { return a < b ? a = b, 1 : 0; }
    template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0; }
    template <typename T> inline T read ()
    {
    T sum = 0, fl = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0';
    return sum * fl;
    }

    inline void proc_status ()
    {
    ifstream t ("/proc/self/status");
    cerr << string (istreambuf_iterator <char> (t), istreambuf_iterator <char> ()) << endl;
    }

    const int Maxn = 20 + 5, Maxs = (1 << 20) + 5;
    const int Mod = 998244353;

    namespace MATH
    {
    inline void Add (int &a, int b) { if ((a += b) >= Mod) a -= Mod; }

    inline int Pow (int a, int b)
    {
    int ans = 1;
    for (int i = b; i; i >>= 1, a = (LL) a * a % Mod) if (i & 1) ans = (LL) ans * a % Mod;
    return ans;
    }
    }

    using namespace MATH;

    int N, M, ALL;
    int A[Maxs];
    int E[Maxs];
    int f[Maxn][Maxs], g[Maxn][Maxs];
    int pw[Maxn * Maxn];

    inline void Init ()
    {
    ALL = (1 << N) - 1;
    pw[0] = 1;
    for (int i = 1; i <= M; ++i) pw[i] = (LL) pw[i - 1] * (Mod + 1) / 2 % Mod;

    for (int i = 1; i <= ALL; ++i)
    {
    int p = i & (-i);
    E[i] = E[i ^ p] + __builtin_popcount (A[p] & i);

    int len = __builtin_popcount (i);
    g[len][i] = (LL) ((len & 1) ? 1 : (Mod - 1)) * pw[E[i]] % Mod;
    }
    }

    inline void DWT (int *A, int n, int op)
    {
    for (int mid = 1; mid < n; mid <<= 1)
    for (int i = 0, len = mid << 1; i < n; i += len)
    for (int j = i; j < i + mid; ++j)
    {
    int x = A[j], y = A[j + mid];
    if (!op) A[j + mid] = (x + y) % Mod;
    else A[j + mid] = (y - x + Mod) % Mod;
    }
    }

    inline void Solve ()
    {
    Init ();

    f[0][0] = 1;
    DWT (f[0], 1 << N, 0);
    for (int i = 0; i <= N; ++i) DWT (g[i], 1 << N, 0);

    for (int i = 1; i <= N; ++i)
    for (int j = 0; j < i; ++j)
    for (int S = 0; S <= ALL; ++S)
    Add (f[i][S], (LL) f[j][S] * g[i - j][S] % Mod);

    DWT (f[N], 1 << N, 1);

    cout << (LL) f[N][ALL] * Pow (2, M) % Mod * Pow (Pow (3, M), Mod - 2) % Mod << endl;
    }

    inline void Input ()
    {
    N = read<int>(), M = read<int>();

    for (int i = 1; i <= M; ++i)
    {
    int x = read<int>() - 1, y = read<int>() - 1;
    A[1 << x] |= (1 << y);
    A[1 << y] |= (1 << x);
    }
    }

    int main()
    {

    #ifdef hk_cnyali
    freopen("F.in", "r", stdin);
    freopen("F.out", "w", stdout);
    #endif

    Input ();
    Solve ();

    return 0;
    }
  • 相关阅读:
    Java读写.properties文件实例,解决中文乱码问题
    web项目的getContextPath()
    PWC6345: There is an error in invoking javac. A full JDK (not just JRE) is required
    Eclipse安装与配置
    Linux基础整理 + 注释
    git命令集合
    遍历List集合的三种方法
    使用jqueryUI和corethink实现的类似百度的搜索提示
    corethink功能模块探索开发(十八)前台页面插入jit前端数据可视化库
    corethink功能模块探索开发(十七)opencmf.php 配置文件
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12361113.html
Copyright © 2011-2022 走看看