魔法手链

题源:
题意:
\(n\) 个珠子,每个珠子可以是 \(1 \to m\),还是套路的旋转后重合算一种填数方案,比较特殊的是,这题给出 \(k\) 种颜色互斥关系,互斥的颜色不得相邻。
\(\rm Analysis:\)
还是 \(\rm burnside\) 引理,只不过求方案的时候各个环不是互相无关了,需要考虑互相影响。
仍然是套路的发现置换的方案数只和环的个数有关,不妨设为 \(f\),那么先大力化一下式子:
\[\begin{aligned}
\sum _ {i = 1} ^ n f((n, i)) 
&= \sum _ {d \mid n} f(d) \sum _ {i = 1} ^ n [(i, n) = d] \\
&= \sum _ {d \mid n} f(d) \varphi(\frac{n}{d})
\end{aligned}
\]
至于 \(f(d)\) 的方案数,这题颜色很少,考虑 \(dp\) 求一波,发现环数为 \(d\) 时,环内不会冲突,只需要考虑环间冲突,而确定了前 \(d\) 个位置,由于每个环内部要求是不动点,则确定了整体,所以只需要考虑前 \(d\) 个位置的取值即可,矩阵快速幂优化就行了,另外,需要额外考虑 \(d = 1\) 时,这时候环内有冲突,合法方案数就是不和自己冲突的颜色数。
\(\rm Code:\)
using i64 = long long;
const int md = 9973;
struct Matrix {
    int n, m;
    std::vector<std::vector<int>> a;
    auto& operator[](const int x) {
        return a[x];
    }
    const auto& operator[](const int x) const {
        return a[x];
    }
    Matrix(int n, int m) : n(n), m(m), a(n, std::vector<int>(m, 0)) {}
    friend Matrix operator*(const Matrix &a, const Matrix &b) {
        Matrix c(a.n, b.m);
        for (int k = 0; k < a.m; ++k) for (int i = 0; i < c.n; ++i) for (int j = 0; j < c.m; ++j) 
            c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % md;
        return c;
    }
    inline int pwer(int idx) {
        // std::cerr << idx << '\n';
        // std::cerr << n << ' ' << m << '\n';
        Matrix res(n, m), now = (*this);
        for (int i = 0; i < n; ++i) 
            res[i][i] = 1;
        for (; idx; idx >>= 1, now = now * now) 
            if (idx & 1) res = res * now;
        // std::cerr << "work: 46" << '\n';
        int sum = 0;
        for (int i = 0; i < n; ++i) 
            sum += res[i][i];
        // std::cerr << sum << '\n';
        return sum % md;
    }
};
signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int T;
    std::cin >> T;
    while (T--) {
        int n, m, k;
        std::cin >> n >> m >> k;
        Matrix init(m, m);
        // std::cerr << n << ' ' << m << ' ' << k << '\n';
        for (int i = 0; i < m; ++i) for (int j = 0; j < m; ++j) 
            init[i][j] = 1;
        // std::cerr << "work: 89" << '\n';
        for (int i = 0; i < k; ++i) {
            int a, b;
            std::cin >> a >> b;
            --a, --b;
            init[a][b] = 0, init[b][a] = 0;
        }
        // std::cerr << "work: 97" << '\n';
        int res = 0;
        for (i64 i = 1; i * i <= n; ++i) {
            // std::cerr << i << '\n';
            if (n % i != 0) 
                continue;
            res = (res + init.pwer(i) * phi(n / i)) % md;
            if (i * i != n) 
                res = (res + init.pwer(n / i) * phi(i)) % md;
            // std::cerr << i << '\n';
        }
        res = res * pwer(n, md - 2) % md;
        std::cout << res << '\n';
    }
}
    我不想就这样沦陷,迷失在黑夜,我将燃烧这生命,就算再壮烈。

 稍微进阶一些的题。
        稍微进阶一些的题。
     
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号