一道记数题

题面

 

笑死,一开始考虑只有一层的情况,推出递推公式之后成功跑偏wwww,然后死也找不出两层情况的递推公式

最后离考试结束还有30min的时候才猛然发现,淦可以直接按照每一列的情况暴力(其实也不暴力)转移啊。

设第一列的颜色是(1,2),再设0颜色是其他m-2种颜色的集合体。那么我们就有了(0,0)(0,1)(0,2)(1,0)(1,2)(2,0)(2,1)这七种状态。

然后我们只需要考虑相邻的两列之间这7种状态的笛卡尔积这7*7种转移的方案数,就可以构造转移矩阵A了

(0,0,0,0,1,0,0) * A^n这个向量的第5维的值就是所求(因为绕了一圈回来必须回到(1,2)这个状态)。

最后还需要再把这个乘上  m*(m-1) 枚举1和2具体是哪个颜色,就是答案了。

 

tip: 构造A其实才是这个题最难的部分,这里留给聪明的你们来思考

 

(然后我在考试结束前的一个if里少写了一个条件WA了,考试结束后10min才改对呜呜呜)

 

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int ha = 1e9+7;

inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}
ll n;
int m;

struct matrix{
    int a[9][9];

    matrix(){
        memset(a,0,sizeof(a));
    }

    matrix operator * (const matrix &u)const{
        matrix r;memset(r.a,0,sizeof(r.a));
        for(int k=0;k<9;k++)
            for(int i=0;i<9;i++)
                for(int j=0;j<9;j++) ADD(r.a[i][j],a[i][k] * (ll)u.a[k][j] % ha);
        return r;
    }   

    inline void construct(){
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++){
                int c = i/3,d = i%3,A = j/3,B = j%3;
                if((c>0 && A == c) || (d>0 && B==d) || (A == B && A>0)) continue;
                if(A > 0 && B > 0) a[i][j] = 1;
                else if((A>0) + (B>0) == 1){
                    if(A>0) a[i][j] = (d>0?max(m-2,0):max(m-3,0));
                    else a[i][j] = (c>0?max(m-2,0):max(m-3,0));
                }
                else{
                    if(c>0 && d>0) a[i][j] = max(m-2,0)*(ll)max(m-3,0)%ha;
                    else if(c>0 || d>0) a[i][j] = max(m-3,0)*(ll)max(m-3,0)%ha;
                    else a[i][j] = add(max(m-3,0),max(m-4,0) * (ll)max(0,m-4)%ha);
                }
            }
    }
};

int main(){
    cin>>n>>m;
    if(m==1){
        cout<<0<<endl;
        return 0;
    }
    matrix x;
    x.construct();

    matrix ans;
    for(int i=0;i<9;i++) ans.a[i][i] = 1;

    for(;n;n>>=1,x=x*x) if(n&1) ans = ans * x;

    cout<<ans.a[5][5] * (ll)m % ha *(ll)(m-1) %ha<<endl;
    return 0;
}

  

 

posted @ 2021-05-16 23:40  蒟蒻JHY  阅读(66)  评论(0编辑  收藏  举报