sgu197 分类: sgu 2015-04-...


注意条件 m<=5,这告诉我们,对于每一列,状态数是很少的,所以怎么乱搞都可以
所以可以递推求解(注意是递推不是动归)。

f(i,S) 表示第 i 列状态为 S 的方案数,有 f(i,S)=f(i1,S) | S>S

用矩阵表示 Fi 表示第 i 列每种状态方案数的矩阵,Fi=TFi1,其中 T 为转移矩阵
所以 Fi=Tn1F1Tn1用快速幂解决即可。


另外 n 需要高精度运算。


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>

#define Get(i,j) (i&(1<<j))

const int MAXM = 6;
struct Matrix{int n ,m ,a[1<<5][1<<5];};
struct BigNumber
{
    int l,num[1<<7];

    void scan()
    {
        static char s[1<<7];
        scanf("%s",s+1),l = strlen(s+1);
        for(int i = 1; i <= l; i++)
          num[i] = s[l-i+1] - '0';      
    }
    BigNumber minus1()
    {
        --num[1];
        for(int i = 1; i <= l; i++)
           if(num[i] < 0) num[i] += 10, num[i+1]--;
           else break;

        if(!num[l]) l--;
        return (*this);     
    }
    BigNumber div2()
    {
        for(int i = 1; i <= l; i++)
        {
          if(num[i]&1) num[i-1]+=10>>1;
          num[i] >>= 1;
        }
        if(!num[l]) l--;
        return (*this);
    }
    int mod2()
    {
        return num[1]&1;
    }
    bool zero()
    {
        if(l) return false;
        else return true;
    }
};

BigNumber N;
int M, p;
Matrix I = {0};
Matrix F = {0}, Ans = {0};
int ans = 0;

Matrix operator *(Matrix A,Matrix B)
{
    Matrix C = {A.n,B.m,{0}};

    for(int i = 0; i < A.n; i++)
      for(int j = 0; j < B.m; j++)
        for(int k = 0; k < A.m; k++)
          C.a[i][j] = (C.a[i][j]+A.a[i][k]*B.a[k][j])%p;

    return C;    
}

Matrix PowerMod(Matrix G,BigNumber k)
{
    Matrix R = I;
    while(!k.zero())
    {
        if(k.mod2()) R = R * G;
        G = G * G, k = k.div2();
    }
    return R;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("sgu197.in","r",stdin);
    freopen("sgu197.out","w",stdout);
#endif

    N.scan();

    std::cin >> M >> p;

    I.n = I.m = F.n = F.m = 1<<M;

    for(int i = 0; i < I.n; i++)
        I.a[i][i] = 1;

    for(int i = 0; i < F.n; i++)
      for(int j = 0; j < F.m; j++)
      {
        F.a[i][j] = 1;  

        for(int k = 1,a,b,c,d; k < M; k++)
        {
            a = Get(i,k-1), c = Get(i,k);
            b = Get(j,k-1), d = Get(j,k);

            if((a && b && c && d) || !(a || b || c || d)) 
                {F.a[i][j] = 0; break;}
        }
      }

    Ans.n = 1<<M, Ans.m = 1;
    for(int i = 0; i < Ans.n; i++)
      Ans.a[i][0] = 1;

    Ans = PowerMod(F,N.minus1()) * Ans; 

    for(int i = 0; i < Ans.n; i++)
      ans += Ans.a[i][0], ans %= p; 

    std::cout << ans << std::endl;   

#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
#endif
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/dashgua/p/4723033.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值