IOI 2024 中国国家集训队互测做题记录

场次 \(\quad\qquad\text{A}\qquad\quad\) 完成情况 \(\quad\qquad\text{B}\qquad\quad\) 完成情况 \(\quad\qquad\text{C}\qquad\quad\) 完成情况
\(\text{Round 1}\) 优惠购物 \(\color{green}\checkmark\) 树哈希 网格图最大流计数
\(\text{Round 2}\) 序列 \(\color{green}\checkmark\) 没有创意的题目名称 \(\color{green}\checkmark\) 傅里叶与交通规划
\(\text{Round 3}\) Permutation Counting 2 化学实验 物理实验
\(\text{Round 4}\) 数据库 左蓝右红 世界沉睡童话
\(\text{Round 5}\) Xor Master 数据结构 \(\color{green}\checkmark\)
\(\text{Round 6}\) Grievous Lady Axium Crisis 落日珊瑚
\(\text{Round 7}\) 不是这一道据数构结题 意念力 重排
\(\text{Round 8}\) 基础寄术练习题 【模板】矩阵快速幂 超现实树
\(\text{Round 9}\) 最短路求和 通道建设 Passage Construction Tree Topological Order Counting
\(\text{Round 10}\) 雷同 水果茶
\(\text{Round 11}\) 挑战积和式 往日之影
\(\text{Round 12}\) 这不是一道数据结构题 \(\color{green}\checkmark\) 不跳棋 \(\color{green}\checkmark\) goods
\(\text{Round 13}\) 天空度假山庄 建设终末树 \(\color{green}\checkmark\) 童话
\(\text{Round 14}\) 命运 崩坏天际线 Since A Light
\(\text{Round 15}\) 括号 染色 coneyisland
\(\text{Round 16}\) 最后的晚餐 彩虹航线 积性函数
\(\text{Round 17}\) 棋盘 \(\color{green}\checkmark\) 区间切割 \(\color{green}\checkmark\) 连连看

\(\color{blue}\mathbf{Round\;1}\)

优惠购物 - 沈吉滪

咕。

树哈希 - 周康阳

咕。

网格图最大流计数 - 吴畅

咕。

\(\color{blue}\mathbf{Round\;2}\)

序列 - 梁城玮

咕。

没有创意的题目名称 - 施开成

先考虑如何更为简洁地刻画合法序列 \(f\) 的形态后再计数(此时暂不考虑 \(f_i<\mathit{lim}_i\)),考虑用若干个特殊值代入函数方程来获得 \(f\) 的一些基本形态。

\(f_i=f_j\)\(i\sim j\),则所给条件即为 \(\forall i+j\le n,f_i+f_j\le n\land f_i+f_j\sim i+j\)。注意到这构成一个等价关系,且若 \(a\sim b,c\sim d\)\(a+b,c+d\) 均不超过 \(n\)),则 \(a+c\sim f_a+f_c=f_b+f_d\sim b+d\),故 \(f_a=f_b\Rightarrow f_{a+1}=f_{b+1}\)。所以 \(f_0,f_1,\cdots,f_n\) 要么互不相同,要么存在 \(p,q(0\le p<q<n)\) 使得 \(f_0,f_1,\cdots,f_{q-1}\) 互不相同且 \(f_{p},f_{p+1},\cdots,f_{q-1}\)\(f_p,f_{p+1},\cdots,f_n\) 的一个循环节。

  • 如果 \(f\) 中的元素互不相同,那么 \(i\sim j\) 等价于 \(i=j\),所以 \(f_i+f_j=i+j\),故 \(f_i=i\)

  • 否则,可记 \(\mathit{len}=q-p\) 为循环节的长度。

    • \(f_0=0\) 时,有 \(f_i\sim i\),由于 \(f_i(0\le i<p)\)\(f\) 中仅出现过一次,所以 \(f_i=i(i<p)\);而对于 \(p\le i<q\),有 \(f_i\ge i\)\(\mathit{len}|(f_i-i)\)。此时若 \(\forall i+j\le n,f_i+f_j\le n\),则 \(f\) 合法(当 \(i+j<p\) 时显然,否则必可取 \(k_1,k_2\) 使得 \(x=i+k_1\cdot\mathit{len},y=j+k_2\cdot\mathit{len}\)\(f_i=x,f_j=y\),此时 \(x+y\ge i+j\ge p\),故 \(f_{f_i+f_j}=f_{x+y}=f_{i+j}\))。
    • 考虑再度解析 \(f_i+f_j\le n\),此时由于 \(i+j\le n\) 的限制,所以 \(q-1\)\(\frac{n}{2}\) 的大小关系非常重要,对其进行分类讨论。
      • \(q-1\le\dfrac{n}{2}\),则所有可能的 \(f_i,f_j\) 都存在对应的 \(i,j\) 使得 \(i+j\le n\),也即 \(f_i\le\dfrac{n}{2}\)
      • \(q-1>\dfrac{n}{2}\),则 \(f_i\le\dfrac{n}{2}(p\le i\le\frac{n}{2})\),而 \(f_i+\mathit{len}\ge q>\dfrac{n}{2}\),故 \(f_i=i\),对于 \(\dfrac{n}{2}<i<q\)\(i\),对应的最紧的 \(j\)\(j=n-i\),所以 \(f_i\le n-(n-i)=i\),又因为 \(f_i\ge i\),所以 \(f_i=i(0\le i<q)\)
    • \(f_0\ne 0\) 时,有 \(f_{f_0+f_0}=f_0\),故 \(p=0,2f_0\equiv 0\pmod{\mathit{len}}\),故 \(\mathit{len}=q\)\(2f_0\) 的因数,所以 \(f_0=k\cdot\mathit{len}\)\(f_0=k\cdot\mathit{len}+\dfrac{\mathit{len}}{2}\),因为此时 \(a\sim b\Leftrightarrow a\equiv b\pmod{\mathit{len}}\),即 \(f_a+f_b\equiv a+b\pmod{\mathit{len}}\)
    • 所以 \(f_0\bmod\mathit{len}\) 的值非常重要,对其进行分类讨论,下文中记 \(g_i=f_i-i\),则条件转化为 \(g_a+g_b\equiv 0\pmod{\mathit{len}}\)
      • \(f_0\bmod\mathit{len}=0\),那么由于 \(\mathit{len}=f_0\le\dfrac{n}{2}\),所以 \(f_0,f_1,\cdots,f_{q-1}\) 都在 \(f\) 中出现至少两次,所以 \(\forall i+j\le n,f_i+f_j\le n\) 等价于 \(f_i\le\dfrac{n}{2}\),而此时 \(g_0\equiv 0\pmod{\mathit{len}}\),故 \(g_i\equiv 0\pmod{\mathit{len}}\),容易发现每一步进行的都是等价转化,所以这是充分必要的。
      • \(2|\mathit{len}\)\(f_0\bmod\mathit{len}=\dfrac{\mathit{len}}{2}\),那么 \(g_0\equiv\dfrac{\mathit{len}}{2}\pmod{\mathit{len}}\),所以 \(g_i\equiv\dfrac{\mathit{len}}{2}\pmod{\mathit{len}}\),代入 \(i=\dfrac{\mathit{len}}{2}-1\)\(f_{\frac{\mathit{len}}{2}-1}\equiv\mathit{len}-1\pmod{\mathit{len}}\),所以 \(f_i\ge\mathit{len}-1\),又因为此时 \(2i\le n\),所以 \(2(\mathit{len}-1)\le n\),故 \(len-1\le\dfrac{n}{2}\),同上一种情况有 \(f_i\le\dfrac{n}{2}\)

综上所述,我们得出了除非 \(f_i=i\),否则 \(f\) 必存在 \(p,q\) 使得后缀 \([p,n]\) 存在循环节 \([p,q)\)\(f_0,f_1,\cdots,f_{q-1}\) 互不相同且为如下四种情况之一:

  • \(f_0=0,q-1\le\dfrac{n}{2},f_i=i(i<p),i\le f_i\le\dfrac{n}{2}(p\le i<q),(q-p)|(f_i-i)(p\le i<q)\)
  • \(f_0=0,q-1>\dfrac{n}{2},f_i=i(i<q)\)
  • \(f_0\ne 0,p=0,q\le\dfrac{n}{2},f_i\le\dfrac{n}{2},f_i-i\equiv0\pmod{q}(i<q)\)
  • \(f_0\ne 0,p=0,2|q,q-1\le\dfrac{n}{2},f_i\le\dfrac{n}{2},f_i-i\equiv\dfrac{q}{2}\pmod{q}(i<q)\)

这时再考虑对于 \(4\) 种情况分别计数,前两种情况枚举 \(\mathit{len}=q-p\) 后再枚举 \(p\) 计算连乘积计算即可;后两种情况枚举 \(q\) 后直接乘法原理计算即可,时间复杂度 \(\mathcal{O}(n^2)\)

点击查看代码
#include <bits/stdc++.h>

using namespace std;

const int N = 2005, P = 998244353;

int qpow(int x, int y = P - 2) {
    int res = 1;
    while (y) {
        if (y & 1) res = 1ll * res * x % P;
        x = 1ll * x * x % P;
        y >>= 1;
    }
    return res;
}

int a[N], f[N], g[N];

signed main() {
    int n; scanf("%d", &n);
    int fl = n;
    for (int i = 0; i <= n; ++i) {
        scanf("%d", &a[i]);
        if (fl == n && i > a[i]) {
            fl = i - 1;
        }
    }
    long long res = (fl == n);
    for (int len = 1; len <= n; ++len) {
        for (int i = n; i >= 0; --i) {
            f[i] = (i == 0 ? 0 : min(a[i], n / 2));
            if (i + len <= n) f[i] = min(f[i], f[i + len]);
            g[i] = (i == 0 ? 0 : a[i]);
            if (i + len <= n) g[i] = min(g[i], g[i + len]);
        }
        for (int i = 0; i <= n; ++i) {
            if (f[i] - i < 0) f[i] = 0;
            else f[i] = (f[i] - i) / len + 1;
            if (g[i] - i < 0) g[i] = 1;
            else g[i] = 0;
        }
        for (int i = 1; i <= n; ++i) g[i] += g[i - 1];
        f[0] = 1;
        for (int p = 0, q = len; q <= n; ++p, ++q) {
            if (p - 1 > fl) continue;
            if (q - 1 <= n / 2) {
                int prod = 1;
                for (int i = p; i < q; ++i) {
                    prod = 1ll * prod * f[i] % P;
                }
                res += prod;
            } else {
                res += (g[q - 1] == (p == 0 ? 0 : g[p - 1]));
            }
        }
    }
    for (int q = 1; q <= n / 2 + 1; ++q) {
        for (int i = n; i >= 0; --i) {
            f[i] = min(a[i], n / 2);
            if (i + q <= n) f[i] = min(f[i], f[i + q]);
        }
        if (q <= n / 2) {
            int prod = 1;
            for (int i = 0; i < q; ++i) {
                if (f[i] < i) prod = 0;
                else prod = 1ll * prod * ((f[i] - i) / q + (i != 0)) % P;
            }
            res += prod;
        }
        if (!(q & 1)) {
            int prod = 1;
            for (int i = 0; i < q; ++i) {
                int t = (i + q / 2) % q;
                if (f[i] < t) prod = 0;
                else prod = 1ll * prod * ((f[i] - t) / q + 1) % P;
            }
            res += prod;
        }
    }
    printf("%lld\n", res % P);
    return 0;
}

傅里叶与交通规划 - 杨敏行

咕。

posted @ 2025-04-09 10:27  hhoppitree  阅读(277)  评论(0)    收藏  举报