[数学][快速幂] Jzoj P4248 n染色

Description

WYF画了一个极为不规则的n边形,画面太美简直不看,没有任意两条边长度是相等的。因为形状太难看了,做他同桌的CWQ看不下去了,趁着WYF上厕所的时间准备用他书包里的m种颜色的彩笔给n边形的边上色。但由于WYF画的实在太大,CWQ不知如何下手,他想知道他有多少种染色方法,能够使得每两条相邻 边不同色。你只需输出答案模10^9+7的结果。
 

Input

一行,仅包含两个正整数n和m。

Output

一个正整数,表示答案模10^9+7的结果
 

Sample Input

3 3

Sample Output

6
 

Data Constraint

对于50%的数据,3≤n≤100000,3≤m≤10;
对于100%的数据,3≤n≤10^18,3≤m≤50。

题解

  • 假设我们有n个点,方案数为A[n]
  • 现在考虑加入第n个点,加入点后左右不同颜色,插入之前的方案数为A[n-1],该点的颜色有m-2中选取的方案
  • 若加入点后左右同色,则删掉一个点后就符合条件了,方案数就为A[n-2],该点的颜色就有m-1种选取的方案
  • 递推公式就是为A[n]=A[n-1]*(m-2)+A[n-2]*(m-1),通项公式为A[n]=(m-1)^n+(m-1)*(-1)^n
  • 递推公式要矩阵乘法加速,通项公式直接快速幂就好了

代码

#include<cstdio>
#define ll long long
#define mo 1000000007
using namespace std;
ll n,m,r;
ll ksm(ll a,ll b) { for (r=1;b;b>>=1,a=a*a%mo) if (b&1) r=r*a%mo; return r; }
int main()
{
    freopen("color.in","r",stdin),freopen("color.out","w",stdout),scanf("%lld%lld",&n,&m);
    printf("%lld
",(ksm(m-1,n)+(m-1)*ksm(-1,n))%mo);
    return 0;
}
原文地址:https://www.cnblogs.com/Comfortable/p/10339586.html