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


    环形染色问题:有一个含有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
  • 相关阅读:
    20201022-1 每周例行报告
    2020高级软件工程“领跑衫”获奖感言
    20201015-3 每周例行报告
    20201008-1 每周例行报告
    竞拍作业
    20201207-总结-作业
    20201126-1每周例行报告
    20201120-1每周例行报告
    20201112 -1每周例行报告
    20201105-1例行报告
  • 原文地址:https://www.cnblogs.com/MekakuCityActor/p/10855721.html
Copyright © 2020-2023  润新知