ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「解题报告」[AGC022F] Checkers

2022-09-10 19:34:38  阅读:190  来源: 互联网

标签:重标 那么 Checkers 正负号 解题 MAXN 2B 集合 AGC022F


题目大意

设 \(x=10^{100}\),在数轴上有 \(n\) 个点,第 \(i\) 个点的坐标为 \(x^i\),每次可以将一个点 \(A\) 变为关于点 \(B\) 的对称点,并把 \(B\) 删除,进行 \(n-1\) 次这样的操作,问最后能得到多少种不同的坐标。

\(n \le 50\)

去看了官方的题解,这里给出官方的 \(O(n^4)\) 做法和比较完整的证明。

思路

首先,\(x\) 特别大,我们可以直接把每个 \(x^i\) 看作是互相独立的。\(A\) 关于 \(B\) 的对称点实际上就是 \(2B-A\)。

首先观察可以发现,得到的所有数肯定都是长成 \(\sum 2^a(-1)^bx^i\) 的形式。

举个例子,比如最后我们得到了 \(2x^1+2x^2+x^3-4x^4\),那么我们发现其实只需要把点的顺序调换一下,就可以得到另外一种结果,比如 \(2x^1+2x^3+x^2-4x^4\)。

所以我们其实只关心最后得到的系数的集合。上面的例子中,我们只关心最后得到的系数集合 \(\{1, 2, 2, -4\}\)。

我们寻找这样的系数集合 \(A\) 都有什么性质:

  1. \(\forall i\in A,\, \exists j,\, \rvert i\lvert=2^j\),即集合中每个元素的绝对值都是 \(2\) 的次幂。

    证明:考虑对称的过程 \(2B-A\),那么实际上每个数就是被乘上了若干个 \(2\)。

  2. \(\sum_{i\in A}i=1\),即集合中元素的和为 \(1\)。

    证明:考虑归纳法证明。

    首先初始值 \(\{1\}\) 的和为 \(1\)。

    若 \(A,B\) 集合均满足以上条件,那么新得到的集合 \(2B-A\) 的和为 \(2 \times 1 - 1 = 1\),得证。

  3. 若 \(2^i\) 或 \(-2^i\) 属于 \(A\),那么 \(2^{i-1}\) 或 \(-2^{i-1}\) 也属于 \(A\)。

    证明:同样归纳法证明,如果 \(A\) 包含的指数范围为 \([0,a]\), \(B\) 包含的指数范围为 \([0,b]\),那么易证 \(2B-A\) 包含的指数范围为 \([0,\max(a,b+1)]\)。

  4. \(2^0\) 和 \(-2^0\) 中有一个且仅有一个属于 \(A\)。

    证明:归纳法,首先 \(2^0,-2^0\) 都不属于 \(2B\),而 \(A\) 中有 \(2^0,-2^0\) 中的其中一个,所以 \(2B-A\) 中有且仅有 \(2^0,-2^0\) 中的一个。

但是这些性质都还只是必要条件,并不充分。我们有一个充要条件如下:

对于每一个 \(i>1\),存在一种将 \(A\) 中的所有 \(\pm 2^i\) 元素前的正负号进行修改的方案,使得 \(\sum_{\rvert x\lvert=2^j,j\in[0,i]}x=1\)(即所有指数小于等于 \(i\) 的数的和为 \(1\))

证明:

  1. 必要性:

    归纳法。

    然后对于每一个 \(i>1\),将 \(B\) 集合中的 \(2^{i-1}\) 元素重标正负号后,得到指数范围在 \([0,i-1]\) 内的数的和为 \(1\),并将 \(A\) 集合中的 \(2^i\) 元素重标正负号后,得到指数范围在 \([0,i]\) 内的数的和为 \(1\)。

    那么 \(2B\) 的指数范围就是 \([1,i]\),且 \(2^i\) 的正负号被重标,那么 \(2B-A\) 就也符合上述性质。

    对于 \(i=1\),根据性质 \(4\),一定可以进行重标正负号使得和为 \(1\)。

  2. 充分性:

    我们想办法构造出一种方案,使得 \(C\) 集合能够被分为 \(2B-A\),并且 \(A,B,C\) 集合均满足以上的所有性质,即可证明充分性。


    首先假设 \(-2^0 \in C\)。

    设 \(k\) 为最小的正整数使得 \(2^k\in C\)。如果对于指数范围在 \([1,k-1]\) 内的所有数都出现了大于等于两次,我们可以构造 \(B=\{-2^0,-2^1,\cdots,-2^{k-2},2^{k-1}\}\),这样 \(2B=\{-2^1,-2^2,\cdots,-2^{k-1},2^k\}\),我们从 \(C\) 集合中刨除掉这些元素,再将元素取反,就得到了 \(A\) 集合。

    首先可以发现 \(B\) 集合满足以上的所有性质,并且 \(A\) 集合满足以上的 \(4\) 条基本性质。


    下面是 \(A\) 集合满足性质 \(5\) 的证明:

    首先对于所有的 \(i\le k\),\(C\) 集合中的 \(\pm2^i\) 在重标正负号后,\(2^i\) 的个数一定大于 \(-2^i\) 的个数,否则和 \(<0\),不满足性质 \(5\)。

    那么在重标正负号的结果中,一定存在一个 \(2^i\)。我们将这个 \(2^i\) 分配给 \(B\) 集合,将剩下的分配给 \(A\) 集合,那么可以证明 \(i\le k\) 的时候性质 \(5\) 是成立的。

    对于 \(i > k\),\(C\) 集合重标正负号的结果都分配给了 \(A\),因为 \(C\) 集合的和为 \(1\),\(B\) 集合的和也为 \(1\),那么 \(A\) 集合的和肯定也为 \(2\times 1 - 1 = 1\),所以也是成立的。

    综上,这样构造出来的 \(A\) 集合是满足性质 \(5\) 的。


    如果对于指数范围在 \([1,k-1]\) 内,存在一个数只出现了一次,那么我们发现再按照上面的方式分配,会导致得到的 \(A\) 集合不满足性质 \(3\)。

    那么我们记最小的只出现了一次的指数为 \(j\)。如果 \(j=1\),那么我们可以令 \(A=\{2^0\}\),并且 \(B\) 为剩下的数除以 \(2\)。对于 \(C\) 的每一个前缀和,将它减去第一个元素 \(-2^0\) 再除以 \(2\) 也等于 \(1\),所以 \(B\) 集合也是符合性质 \(5\) 的。

    如果 \(j>1\),那么指数范围在 \([0,j-1]\) 内的数的和的最大值应该为 \(-2^0+2(-2^1-2^2-\cdots -2^{j-1})=-2^{j+1}+3\),发现这个数永远小于 \(-2^j\),那么无论如何修改 \(2^j\) 前面的正负号都无法使得前缀和等于 \(1\),所以是不存在 \(j>1\) 的情况的。

于是我们证明了性质 \(5\) 是一个充要条件。

于是,我们只需要统计满足以上五个条件的集合数有多少种即可。

设 \(f_{i,j}\) 表示已经放了 \(i\) 个元素,并且这些元素的和为 \(1+jV\),其中 \(V\) 为现在要放的 \(2\) 的次幂是多少。

那么我们枚举选了 \(a\) 个 \(V\),选了 \(b\) 个 \(-V\),那么元素的和就变为了 \(1+(j+a-b)V\)。因为下一个填的数就要比现在的数乘 \(2\),所以 \(f_{i,j}\) 转移到 \(f_{i+a+b,\frac{j+a-b}{2}}\)。

我们需要满足将这些数任意标正负号之后,和为 \(1\),那么我们只需要满足 \(j \equiv a+b \pmod 2\) 且 \(a+b\ge \rvert j\lvert\) 即可。

然后考虑对这个系数集合分配原来的 \(x^i\),这个就是多重组合数的形式(\(\frac{n!}{\prod a!}\)),我们可以把 \(\frac{1}{\prod a!}\) 的部分拆到转移上,也就是 \(f_{i,j} \times \frac{1}{a!b!}\rightarrow f_{i+a+b,\frac{j+a-b}{2}}\)。

初始状态为 \(f_{0,-1}=1\),答案为 \(n!f_{n,0}\)。

需要注意,为了满足性质 \(4\),需要特殊判断一下,当 \(i=0\) 时,必须满足 \(a+b=1\) 时才可以转移。

Code

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 55, P = 1000000007;
int f[MAXN][MAXN << 1];
int n;
int fac[MAXN], inv[MAXN];
int qpow(int a, int b) {
    int ans = 1;
    while (b) {
        if (b & 1) ans = 1ll * ans * a % P;
        a = 1ll * a * a % P;
        b >>= 1;
    }
    return ans;
}
int main() {
    scanf("%d", &n);
    f[0][MAXN + -1] = 1;
    fac[0] = 1;
    for (int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % P;
    inv[n] = qpow(fac[n], P - 2);
    for (int i = n; i >= 1; i--) inv[i - 1] = 1ll * inv[i] * i % P;
    for (int i = 0; i < n; i++) {
        for (int j = -n; j <= n; j++) if (f[i][j + MAXN]) {
            for (int a = 0; a <= n; a++) {
                for (int b = 0; i + a + b <= n; b++) if ((a || b) && ((j + a + b) % 2 == 0) && a + b >= abs(j)) {
                    if (i == 0 && a + b != 1) continue;
                    f[i + a + b][(j + a - b) / 2 + MAXN] = (f[i + a + b][(j + a - b) / 2 + MAXN]
                         + 1ll * f[i][j + MAXN] * inv[a] % P * inv[b]) % P;
                }
            }
        }
    }
    printf("%lld\n", 1ll * f[n][MAXN + 0] * fac[n] % P);
    return 0;
}

标签:重标,那么,Checkers,正负号,解题,MAXN,2B,集合,AGC022F
来源: https://www.cnblogs.com/apjifengc/p/16678043.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有