[环形染色][公式推导/矩阵快速幂]

环形染色问题:有一个含有n个珠子的环,每个相邻珠子不能被涂上相同的颜色,一共有m种染料,求总方案数。

分析:设Fn表示n个珠子的方案数,考虑在n-1个珠子里插入一个珠子,那么得到的方案数应该是(m-2)*Fn-1,再考虑把n-2个珠子其中一个珠子分成两份并且在中间插入一个珠子,则得到的方案数应该是(m-1)*Fn-2,所以Fn=(m-1)*Fn-2+(m-2)*Fn-1

求解:当n很大时,递推求解Fn的时间复杂度就不能接受了,此时有两种方法解决。

方法1:推出Fn的公式=> 上述递推式是一个二阶常系数递推式,可以解得通项公式为 Fn=(m-1)^n+(-1)^n * (m-1)

方法2:使用矩阵快速幂求解=>使用矩阵快速幂的时候一定要注意 F1=0...而不是F1=m

链接:https://ac.nowcoder.com/acm/contest/879/A
来源:牛客网

题目描述

thewindandrainisinmywayandnevergoingawaythewindandrainisinmywayandnevergoingaway
你在一个有 n 个城市的国家中行走,城市从 1 到 n 依次编号
任意两个城市之间都有一条双向道路可以通行,且你可以花一天的时间从当前所在的城市到达任意一个别的城市
由于你比较闲的无聊,所以你不会连续两天都呆在同一个城市,也就是说每天你所在的城市都不相同(这句话的意思是,对于相邻的两天,你所在的城市应该不同)
一开始你在 1 号城市,求经过 k 天后你回到 1 号城市的方案数
当然如果不存在任意一种方案就输出 0 就好了

输入描述:

第一行两个整数 n,k

输出描述:

一行一个整数表示答案对 998244353 取模后的结果
示例1

输入

复制
1 1

输出

复制
0
1)公式法
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define debug(x) cout<<"["<<#x<<"]"<<"  "<<x<<endl;
 5 const ll mod=998244353;
 6 ll mypow(ll x,ll y){
 7     ll ans=1;
 8     while(y){
 9         if(y&1)ans=ans*(x%mod)%mod;
10         x=(x%mod)*(x%mod)%mod;
11         y/=2;
12     }
13     return ans;
14 }
15 int main()
16 {
17     ll n,k;
18     cin>>n>>k;
19     k--;
20     ll ans=(mypow(n-1,k+1)+mypow((-1ll),k+1)*(n-1)+mod*2)%mod*mypow(n,mod-2)%mod;
21     printf("%lld
",ans);
22     return 0;
23 }
View Code

2)矩阵快速幂

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define debug(x) cout<<"["<<#x<<"]"<<"  "<<x<<endl;
 5 ll w[2][2],e[2][2];
 6 const int N=2;
 7 const ll mod=998244353;
 8 ll tmp[N][N];
 9 ll mypow(ll x,ll y){
10     ll ans=1;
11     while(y){
12         if(y&1){
13             ans=ans*x%mod;
14         }
15         x=(x%mod)*(x%mod)%mod;
16         y/=2;
17     }
18     return ans;
19 }
20 void multi(ll a[][N],ll b[][N],int n)
21 {
22     memset(tmp,0,sizeof tmp);
23     for(int i=0;i<n;i++)
24         for(int j=0;j<n;j++)
25         for(int k=0;k<n;k++)
26         {tmp[i][j]+=(a[i][k]%mod)*(b[k][j]%mod);tmp[i][j]%=mod;}
27     for(int i=0;i<n;i++)
28         for(int j=0;j<n;j++)
29         a[i][j]=tmp[i][j];
30 }
31 ll res[N][N],q[N][N];
32 void Pow(ll a[][N],int n)
33 {
34     memset(res,0,sizeof res);//n是幂,N是矩阵大小
35     for(int i=0;i<N;i++) res[i][i]=1;
36     while(n)
37     {
38         if(n&1)
39             {multi(res,a,N);}//res=res*a;复制直接在multi里面实现了;
40         multi(a,a,N);//a=a*a
41         n>>=1;
42        // debug(res[0][0]);
43     }
44 }
45 ll n,k;
46 void init(){
47     w[0][0]=-1;
48     w[0][1]=n-1;
49     w[1][0]=0;
50     w[1][1]=n-1;
51     q[0][0]=(n)*((n-1))%mod;
52     q[1][0]=(n)*((n-1))%mod;
53 }
54 int main()
55 {
56     scanf("%lld%lld",&n,&k);
57     init();
58     Pow(w,k-2);
59    // debug(res[0][0]);
60     multi(res,q,2);
61    // debug(res[0][0]);
62     printf("%lld
",res[0][0]*mypow(n,mod-2)%mod);
63     return 0;
64 }
View Code
原文地址:https://www.cnblogs.com/MekakuCityActor/p/10855721.html