首页 > 其他分享 >【题解】P4916 [MtOI2018]魔力环

【题解】P4916 [MtOI2018]魔力环

时间:2023-01-30 10:45:10浏览次数:40  
标签:frac gcd limits 题解 sum MtOI2018 循环 P4916 复杂度

锐评:小学奥数测验

思路

环 + 循环同构,一眼知群论。

考虑类似 P4980 【模板】Pólya 定理,用 Burnside 引理处理。

令 \(G\) 为循环任意次构成的置换群,研究的 “点” 为染色过的环,根据 Burnside 引理知所求为 \(\frac{1}{n} \sum\limits_{i = 1}^n g(i)\),其中 \(g(i)\) 表示置换为旋转 \(i\) 次时的不动点数量。

因为将长度为 \(n\) 的环旋转 \(i\) 次的置换共有 \(\gcd(i, n)\) 个循环,所以令 \(f(x)\) 表示置换中的循环个数为 \(x\) 时的不动点数量,则 \(g(x) = f(\gcd(x, n))\).

所以答案所求可以写成 \(\frac{1}{n} = \sum\limits_{i = 1}^n g(i) = \frac{1}{n} \sum\limits_{i = 1}^n f(\gcd(i, n)) = \frac{1}{n} \sum\limits_{d \mid n} f(d) \varphi(\frac{n}{d})\),只需要考虑求出 \(f\) 即可。

不妨给每个循环从 \(0\) 开始标号。根据不动点的定义知同一循环内的点必须颜色相同。

方便起见令 \(x\) 代表循环的长度而非个数。现在求 \(f\) 可以转化成:

对于 \(\frac{n}{x}\) 个长度为 \(x\) 的循环,考虑将其中的 \(\frac{m}{x}\) 的循环全部染成黑色,并且不能有连续 \(k\) 个循环同时是黑色。求所有方案数。

令 \(S(n, m)\) 为:对于长度为 \(n\) 的环,将其中的 \(m\) 个点染成黑色,并且不能有超过 \(k\) 个连续的循环同时是黑色的方案总数。将循环缩成点,上面的问题实际上等价于求 \(S(\frac{n}{x}, \frac{m}{x})\).

因为题目钦定黑色个数,所以可以考虑把这些黑色点取出来,在剩下白点的 \(n - m\) 个空隙(白点成环)中合法地插入。

环上计数不好处理,考虑固定环的起始和结束结点,钦定首尾之间的黑色点个数,这样就可以转化成序列问题。

所以求 \(S(n, m)\) 等价于求 \(\sum\limits_{i = 0}^k (i + 1) R(n - m - 1, m - i)\),其中 \(R(n, m)\) 表示:在 \(n\) 个点中将 \(m\) 个点染成黑色,要求没有超过连续 \(k\) 个点都是黑色的方案总数。

\(i + 1\) 是 \(i\) 个黑点划分到链首和链尾的方案总数。

所以问题转化成求 \(R(n, m)\).

这里 \(R(n, m)\) 又等价于在 \(n\) 个空盒中放入 \(m\) 个黑球,要求不存在一个盒中有超过 \(k\) 个黑球的方案总数。

这个可以容斥求,具体只需要钦定超过限制的盒子数量即可:

\(R(n, m) = \sum\limits_{i = 0}^{\min(\lfloor \frac{m}{k + 1} \rfloor, n)} (-1)^i {n \choose i} T(n, m - i(k + 1))\),其中 \(T(n, m)\) 表示将 \(n\) 个相同的球放入 \(m\) 个不同的盒子(允许空盒)的方案总数。

\(T(n, m)\) 直接插板得到 \(T(n, m) = {n + m - 1 \choose n - 1}\).

这里容斥的复杂度是 \(O(\frac{m}{k})\). 求 \(S(n, m)\) 一共需要求 \(k\) 次,所以单次求 \(S(n, m)\) 的复杂度是 \(O(m)\).

观察答案的形式 \(\frac{1}{n} \sum\limits_{d \mid n} f(d) \varphi(\frac{n}{d})\),发现总复杂度是 \(O(\sigma_1(n))\),根据数论常识得复杂度为 \(O(n \log n)\).

注意到只有 \(i \mid n, i \mid m\) 的 \(i\) 才能保证 \(S(\frac{n}{i}, \frac{m}{i})\) 有值,所以只需要枚举 \(\gcd(n, m)\) 的因数,总复杂度为 \(O(\sigma_1(\gcd(n, m))\).

代码

#include <cstdio>
using namespace std;

#define min(x, y) (x <= y ? x : y)

const int maxn = 1e5 + 5;
const int mod = 998244353;

int n, m, k, coe;
int fac[maxn], invf[maxn];

int gcd(int a, int b) { return (!b ? a : gcd(b, a % b)); }

int phi(int x)
{
    int res = x;
    for (int i = 2; i * i <= x; i++)
    {
        if (x % i == 0)
        {
            res = res / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    }
    if (x > 1) res = res / x * (x - 1);
    return res;
}

void init()
{
    fac[0] = invf[0] = fac[1] = invf[1] = 1;
    for (int i = 2; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % mod, invf[i] = 1ll * invf[mod % i] * (mod - mod / i) % mod;
    coe = invf[n];
    for (int i = 1; i <= n; i++) invf[i] = 1ll * invf[i - 1] * invf[i] % mod;
}

int C(int n, int m) { return (n < m ? 0 : 1ll * fac[n] * invf[m] % mod * invf[n - m] % mod); }

int T(int n, int m) { return C(n + m - 1, n - 1); }

int R(int n, int m)
{
    int res = 0;
    for (int i = 0, nega = 1; i <= min(m / (k + 1), n); i++, nega = -nega)
    {
        res = (res + 1ll * nega * C(n, i) * T(n, m - i * (k + 1)) % mod) % mod;
        res = (res + mod) % mod;
    }
    return res;
}

int S(int n, int m)
{
    if (m <= k) return C(n, m);
    int res = 0;
    for (int i = 0; i <= k; i++) res = (res + 1ll * (i + 1) * R(n - m - 1, m - i) % mod) % mod;
    return res;
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    init();
    if (n == m) return puts(k == m ? "1" : "0"), 0;
    int res = 0, g = gcd(n, m);
    for (int i = 1; i * i <= g; i++)
        if (g % i == 0)
        {
            res = (res + 1ll * S(n / i, m / i) * phi(i) % mod) % mod;
            if (g / i != i) res = (res + 1ll * S(n / (g / i), m / (g / i)) * phi(g / i) % mod) % mod;
        }
    res = 1ll * res * coe % mod;
    printf("%d\n", res);
    return 0;
}

标签:frac,gcd,limits,题解,sum,MtOI2018,循环,P4916,复杂度
From: https://www.cnblogs.com/lingspace/p/p4916.html

相关文章

  • 【题解】洛谷-P3270 [JLOI2016]成绩比较
    式子有点长,步骤有点多,所以写一下。题目要求恰好\(k\)人被吊打的方案数,容易想到二项式反演,设\(f(k)\)为钦定\(k\)人其他任意的方案数,\(g(k)\)为恰好\(k\)人的方案......
  • 题解 CF277E【Binary Tree on Plane】
    费用流。可以将原问题转化为类似于匹配的问题,只不过这种匹配并不是一对一的。具体地,将每个点\(u\)拆成两个点\(u_\text{fa},u_\text{son}\),设源点为\(s\)、汇点为\(t......
  • 题解:【CODE FESTIVAL 2016 Grand Final】90 and 270
    题目链接经典增量构造题。不妨从是否存在构造开始考虑:根据多边形内角和的公式容易得出给定的度数和必须等于\((n-2)\times180^{\circ}\),才有解。换一个角度思考,又因......
  • 【题解】P4707 重返现世
    隔壁友校的初一已经开始做这种题了,准老年选手感到恐惧。思路Min-Max容斥。首先考虑到\(|n-k|\leq10\),感觉有大力做法,考虑用Min-Max容斥求期望。设全集\(U\)......
  • [AHOI2009] 中国象棋 题解
    每行每列的炮数量\(\leq2\),那么整个图就可以被分解为一些环和链。考虑答案的二元生成函数,显然环和链分别的生成函数都是平凡的多项式,而答案的多项式无非是加起来后求exp......
  • 黑白树 题解
    看了半天题解代码大概明白他在干啥了。写篇题解总结一下。题面:一棵树,每个点黑色或白色,有权值。五个操作:改变一个点颜色。使点\(x\)所在的同色连通块权值加\(val\)。......
  • CF468E Permanent 题解
    考虑暴力状压DP。按行DP,记录列哪些被选过,可以做到\(O(2^kk^2)\)。注意到某一列扫完了之后这一列选没选过不重要,可以减少这里的状态。简单优化一下,每次选择最少的一列......
  • CF1033E 题解
    题意传送门交互题,给定一个简单连通图,你可以询问一个点集\(s\),返回其导出子图的边数。判断此图是否为二分图:若是,输出其中一部点的集合;否则输出任一个奇环。最多询问\(20......
  • Good Bye 2022 简要题解
    从这里开始比赛目录过气选手留下了只会套路的眼泪。sad......ProblemA KoxiaandWhiteboards相信大家都会.jpgCode#include<bits/stdc++.h>using......
  • 题解:【CF226D】The table
    题目链接调整构造。发现\(n\)和\(m\)较小只有\(100\),因此可以考虑尝试进行修改从而不断逼近答案。容易发现如果将某一行或列上的数字翻转,那么得到的新的和一定与原......