[环形染色][公式推导/矩阵快速幂]
环形染色问题:有一个含有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 号城市的方案数
你在一个有 n 个城市的国家中行走,城市从 1 到 n 依次编号
任意两个城市之间都有一条双向道路可以通行,且你可以花一天的时间从当前所在的城市到达任意一个别的城市
由于你比较闲的无聊,所以你不会连续两天都呆在同一个城市,也就是说每天你所在的城市都不相同(这句话的意思是,对于相邻的两天,你所在的城市应该不同)
一开始你在 1 号城市,求经过 k 天后你回到 1 号城市的方案数
当然如果不存在任意一种方案就输出 0 就好了
输入描述:
第一行两个整数 n,k
输出描述:
一行一个整数表示答案对 998244353 取模后的结果
示例1
输出
复制0
View Code
View Code
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\n",ans); 22 return 0; 23 }
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\n",res[0][0]*mypow(n,mod-2)%mod); 63 return 0; 64 }