NC19115 选择颜色

题目

题目描述

\(n\) 个人排成一个环形,每个人要从 \(c\) 种颜色中选择一个。

牛牛希望相邻的人选择的颜色是不同的

问有多少种方案。

输出方案数对 \(10007\) 取模的结果。

人是有顺序的,环旋转同构算不同的方案。

输入描述

输入只有一行,包含用空格分开的两个整数,表示 \(n\)\(c\)

输出描述

输出一行一个整数,表示答案。

示例1

输入

4 3

输出

18

示例2

输入

1000000000 100

输出

726

说明

\(10007\) 取模。

备注

对于所有数据: \(3 \leq n \leq 1000000000, 3 \leq c \leq 100\)
\(20\) 分: \(c \leq 3\)
\(40\) 分: \(c \leq 4\)
\(70\) 分: \(n \leq 10000\)

题解

知识点:计数dp,运算优化。

\(f_i\) 为考虑到了第 \(i\) 个人,并且第 \(i\) 个人与第 \(1\) 个人颜色是相同的情况数。

\(g_i\) 为考虑到了第 \(i\) 个人,并且第 \(i\) 个人与第 \(1\) 个人颜色是不同的情况数。

显然 \(f_i = g_{i-1}\) ,而 \(g_i = (c-1)f_{i-1} + (c-2)g_{i-1}\)

\(g_i\) 表达出来,\(g_i = (c-1)g_{i-2} + (c-2)g_{i-1}\) ,随后解递推:

  1. 二阶线性递推方程的特征方程是 \(x^2 = px+q\) ,即 \(x^2 = (c-2)x + (c-1)\) ,解得 \(x = c-1 \ or\ -1\)
  2. 于是有 \(g_i = C_1(c-1)^{n-1}+C_2(-1)^{n-1}\) ,代入初始条件 \(g_1 = 0\)\(g_2 = (c-1)f_1 = (c-1)c\) ,得 \(C_1 = c-1 = -C_2\)
  3. 因此通项公式是 \(g_i = (c-1)^i + (c-1)(-1)^i\)

由于最后一个人肯定不能和第一个相同,因为是环状的,所以答案就是 \(g_n\)

用快速幂处理即可。

时间复杂度 \(O(\log n)\)

空间复杂度 \(O(1)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int mod = 1e4 + 7;

int qpow(int a, int k) {
    ll ans = 1;
    while (k) {
        if (k & 1) ans = a * ans % mod;
        k >>= 1;
        a = a * a % mod;
    }
    return ans;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, c;
    cin >> n >> c;
    cout << (qpow(c - 1, n) + (c - 1) * qpow(-1, n) + mod) % mod << '\n';
    return 0;
}
posted @ 2022-06-23 22:18  空白菌  阅读(73)  评论(0编辑  收藏  举报