题目:[[2024.10.21 题目]] ## 串串串 有两个长度为 $n,m$ 的 $0/1$ 字符串 $S,T$,给定 $Q$ 次询问,每次询问给出 $(l_1,r_1,l_2,r_2)$,其中 $r_1-l_1=r_2-l_1$,令 $a=S_{l_1\sim r_1},b=T_{l_2\sim r_2}$,求 $a_i\ne b_i$ 的位置数量对 $2$ 取模的结果。 --- 手推可以发现,交换区间内的任意两个位置 $i,j$,答案的奇偶性都是不变的。具体而言:如果位置 $i$ 与位置 $j$ 相等,那么交换了就跟没交换一样;如果两个位置上的数不一样,那么答案可能会根据实际情况加 $2$ 或减 $2$,答案的奇偶性没有变化。 因此我们只需要使用两个前缀和数组记录 $S$ 和 $T$ 任意区间的 $1$ 的数量,如果询问的两个区间 $1$ 的数量相等就输出 $0$,否则输出 $1$。 ```cpp // 出题人,柠檬熟了 #include <fstream> using namespace std; using LL = long long; const LL kMaxN = 2e5 + 5; ifstream cin("string.in"); ofstream cout("string.out"); LL p1[kMaxN], p2[kMaxN], n, m, q; char s[kMaxN], t[kMaxN]; int main() { cin.tie(0)->sync_with_stdio(0); cin >> n >> m >> (s + 1) >> (t + 1) >> q; for (LL i = 1; i <= n; i++) { p1[i] = p1[i - 1] + (s[i] == '1'); } for (LL i = 1; i <= m; i++) { p2[i] = p2[i - 1] + (t[i] == '1'); } for (LL l1, r1, l2, r2; q; q--) { cin >> l1 >> r1 >> l2 >> r2; cout << (LL)((p1[r1] - p1[l1 - 1]) % 2 != (p2[r2] - p2[l2 - 1]) % 2) << '\n'; } return 0; } ``` ## 方格计数 给定 $H,W$,有 $(H+1)\times (W+1)$ 的网格,现在要在网格上找 $N$ 个不同的结点,使得这些点在同一条直线上,并且在这条直线上相邻点的距离不小于 $D$,求方案数对 $10^9+7$ 取模的值。 --- 枚举 $N$ 个点分别在哪个位置上肯定不行,因此我们不如枚举 $N$ 个点所在的直线上。很容易想到枚举直线的斜率,然后再枚举直线上的两个端点,在算出答案。但是这样子代码过于复杂,而且枚举斜率很容易重复。 小学老师交过我们一件事:「两点确定一条直线」。这也就意味着我们根本就没有必要枚举直线的斜率,我们可以直接枚举直线两边的端点,即可确定这一条直线/线段。根据初中老师所讲的知识,假设两点之间 $x$ 坐标差值为 $\Delta x$,$y$ 坐标差值为 $\Delta y$,则这两点之间连接的线段将会在网格上经过 $\gcd(\Delta x,\Delta y)$ 个点。 此时我们已经选择了两个端点,因此还需要选择 $N-2$ 个直线上的端点。由于题目中指出相邻两点距离至少为 $D$,因此我们将直线经过的点编号,令任意相邻两个点编号差不能小于 $l$,这时学过组合数的都应该知道了,答案为 $ \binom{g-(l-1)\times (N-3)-2\times k+1}{N-2} $ 因此我们预处理杨辉三角用来计算组合数,或者预处理阶乘使用费马小定理计算组合数(因为在这题当中模数为质数)。此时时间复杂度为 $\mathcal O(W^2H^2)$,可以通过 $30$ 分。 接下来考虑如何得到满分,其实非常简单。不难发现,在枚举的过程中,有很多直线它们斜率相等或互为倒数,这时我们就可以把这些直线看成相等的,同一枚举并计算。假设有一个矩形框,这条直线就是矩形的对角线,矩形的宽为 $w$,高为 $h$,则为同样的矩形有 $(W-w+1)(H-h+1)$ 个,乘上即可。 最后就是细节的处理了。对于 $h,w\ne 0$ 的矩形,我们需要将答案翻倍,很明显是因为对角线有 $2$ 条。这样我们就成功地将时间复杂度优化到了 $\mathcal O(WH)$,可以通过 $100$ 分。 ```cpp #include <fstream> #include <cmath> using namespace std; using LL = long long; const LL kMaxN = 3005, kMod = 1e9 + 7; ifstream cin("count.in"); ofstream cout("count.out"); LL c[kMaxN][kMaxN], f[kMaxN], t, n, w, h, d, ans; void pre() { cin.tie(0)->sync_with_stdio(0); c[0][0] = 1; // 没有初始化 for (LL i = 1; i <= 3000; i++) { c[i][0] = 1; for (LL j = 1; j <= i; j++) { c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % kMod; } } // f[0] = 1; // for (int i = 1; i <= 3000; i++) { // f[i] = f[i - 1] * i % kMod; // } } LL gcd(LL a, LL b) { return !b ? a : gcd(b, a % b); } double dis(LL x, LL y) { return sqrt(x * x + y * y); } // LL pow(LL a, LL b) { // LL res = 1; // for (; b; b /= 2) { // b & 1 && (res = res % a % kMod); // a = a * a % kMod; // } // return res; // } // // LL inv(LL x) { return pow(x, kMod - 2); } LL fuck(LL i, LL j) { LL g = gcd(i, j), l = (LL)ceil(1.0 * d / dis(i / g, j / g)) /* 差 */; if ((n - 1) * l > g) { return 0; } return c[g - (n - 3) * (l - 1) - 2 * l + 1][n - 3 + 1] * // 组合数 (i && j ? 2 : 1) % kMod * // 一正一反 (w - i + 1) % kMod * // 横方向 (h - j + 1) % kMod; // 竖方向 } int main() { pre(); for (cin >> t; t; t--) { cin >> n >> w >> h >> d; // BYD 的,没有特判调了半小时,我 /* */ if (n == 1) { cout << (w + 1) * (h + 1) << '\n'; continue; } ans = 0; for (LL i = 0; i <= w; i++) { for (LL j = 0; j <= h; j++) { if (!i && !j) { continue; } ans = (ans + fuck(i, j)) % kMod; } } cout << ans << '\n'; } return 0; } ``` ## 树数树 有 $n$ 个结点的树,现在求一个最长的序列 $a$,满足: - $\forall i\in(1,m]$,$a_i$ 为 $a_{i-1}$ 的祖先或 $a_{i-1}$ 为 $a_i$ 的祖先; - $\forall 1\le i<j\le m$,$a_i\ne a_j$。 $T$ 组数据。 --- 不会写,只判断了树为链或菊花的情况,获得 $30$ 分,赛后发现没有特判完全二叉树的形状,本来能拿 $40$ 分。本体正解合并堆(左偏树),虽然好渴鹅学过,但是没有发现!你干嘛——哈哈哎哟~ ## 序列 对于数 $S$,它的数位和为 $10$ 的字段被称作 se 序列,如果它的被一个数位都至少在一个 se 序列中,则称 $S$ 是 II 数。给定 $n$ 和 $b_i$ $(i\in [0,10))$,令 $a_i=\cfrac{b_i}{\sum\limits_{j=0}^9 b_j}$(满足 $\sum\limits_{i=0}^9a_i=1$),随机生成一个 $[0,10^n)$ 范围内的数,每一位上生成数字 $i$ 的概率为 $a_i$,求这个数为 II 数的概率,答案对 $10^9+7$ 取模。 --- 不会写,对于 $n=1$ 的情况特判并输出 $0$,在 widwolf 上面理所应当地获得了 $5$ 分的好成绩,但是在 lemon 上面没有分,老师说题面改了(具体的可以查看 [[2024.10.21 星期一]]),不知道最后在 linux 上面能够获得多少分,反正都一样。 ## 总结 - **排名**:$4$; - **比赛分数**:$235/400$; - **情况**:相比 [[2024.10.20 模拟赛]],还可以; - **问题**:突然不会左偏树的应用了。