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}\) ,随后解递推:
- 二阶线性递推方程的特征方程是 \(x^2 = px+q\) ,即 \(x^2 = (c-2)x + (c-1)\) ,解得 \(x = c-1 \ or\ -1\) 。
- 于是有 \(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\)。
- 因此通项公式是 \(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;
}
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16406967.html