SGU 197 Nice Patterns Strike Back || ZOJ 2317 Nice Patterns Strike Back

题目链接~~>

做题感悟:做了这题感觉学习了不少东西,首先是关于状态压缩推公式学会了。

解题思路:

                 构造矩阵: B[ i ][ j ] (i , j 为状态,0 <= i ,j  <= (1<<m) - 1 ) , 如果 B[ i ] [ j ]  等于 1 代表状态 i 与状态 j 相互兼容(i , j 可以在相邻两行),如果为 0 代表不可以相邻,还要有一个原始矩阵 A ,(1<<m)-1 行 ,1列的矩阵  ,代表第一行各种状态的方案数,这样 B *  A 就得到了第二行各种状态的方案数,so ~ > A^( n - 1) * B 就得到了第 n 行的方案数,最后将最终矩阵相加就是总的方案数。因为这题指数比较大,so~>需要大数模拟除 2 的操作就可以了

代码:

#include<iostream>
#include<sstream>
#include<map>
#include<cmath>
#include<fstream>
#include<queue>
#include<vector>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<bitset>
#include<ctime>
#include<string>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std  ;
#define INT  long long int
#define L(x)  (x * 2)
#define R(x)  (x * 2 + 1)
const int INF = 0x3f3f3f3f ;
const double esp = 0.0000000001 ;
const double PI = acos(-1.0) ;
const int MY = 1400 + 5 ;
const int MX = 1005 + 5 ;
int S ,m ;
int d[MX] ;
INT mod ;
struct STR
{
    int n ,d[MX] ;
    STR()
    {
        n = 0 ;
        memset(d ,0 ,sizeof(d)) ;
    }
    STR operator - (int x)
    {
       STR s ;
       s.n = n ;
       for(int i = n - 1 ;i >= 0 ; --i)
        if(d[i])
        {
            d[i]-- ;
            for(int j = i+1 ;j < n ; ++j)
                d[j] = 9 ;
                break ;
        }
       if(d[0] == 0)
       {
           for(int i = 1 ;i < n ; ++i)
              s.d[i-1] = d[i] ;
              s.n-- ;
       }
       else
          for(int i = 0 ;i < n ; ++i)
                 s.d[i] = d[i] ;
       return s ;
    }
    STR operator >> (int x)
    {
       STR s ;
       int a[MX] ,num = 0 ,sum = 0 ;
       for(int i = 0 ;i < n ; ++i)
       {
           sum = sum*10 + d[i] ;
           if(sum >= 2)
           {
               a[num++] = sum / 2 ;
               sum = sum%2 ;
           }
           else if(num)
               a[num++] = 0 ;
       }
       for(int i = 0 ;i < num ; ++i)
           s.d[i] = a[i] ;
           s.n = num ;
       return s ;
    }
    bool operator &(int x)
    {
        if(d[n-1]&1)  return true ;
        return false ;
    }
} ;
struct M
{
    INT p[33][33] ;
    M()
    {
        memset(p ,0 ,sizeof(p)) ;
    }
    void init()
    {
        for(int i = 0 ;i < S ; ++i)
          p[i][i] = 1 ;
    }
} ;
bool judge(int x ,int y)
{
    for(int i = 0 ;i < m-1 ; ++i)
       if(((x&(1<<i)) && (x&(1<<(i+1))) && (y&(1<<i)) && (y&(1<<(i+1))))||
         (!(x&(1<<i)) && !(x&(1<<(i+1))) && !(y&(1<<i)) && !(y&(1<<(i+1)))))
               return   false ;
    return   true ;
}
M Pre() // 构造矩阵
{
    M c ;
    for(int i = 0 ;i < S ; ++i)
      for(int j = i ;j < S ; ++j)
         if(judge(i ,j))
              c.p[i][j] = c.p[j][i] = 1 ;
    return c ;
}
M operator * (const M& a ,const M& b)  // 矩阵乘法
{
    M c ;
    for(int i = 0 ;i < S ; ++i)
      for(int k = 0 ;k < S ; ++k)
        if(a.p[i][k])
          for(int j = 0 ;j < S ; ++j)
             c.p[i][j] = (c.p[i][j] + a.p[i][k]*b.p[k][j]) %mod ;
    return c ;
}
M pow(M a ,STR k)  // 快速幂
{
    M b ;
    b.init() ;
    while(k.n)
    {
        if(k&1)
            b = b * a ;
        a = a * a ;
        k = k>>1 ;
    }
    return b ;
}
int main()
{
    char str[MX] ;
    while(cin>>str>>m>>mod)
    {
        S = (1<<m) ;       // 总状态
        STR s ;
        for(int i = 0 ;i < strlen(str) ; ++i)
           s.d[i] = str[i]-'0' ;
        s.n = strlen(str) ;
        s = s - 1 ;
        M c = Pre() ;
        M b = pow(c ,s) ;
        INT ans = 0 ;
        for(int i = 0 ;i < S ; ++i)
          for(int j = 0 ;j < S ; ++j)
             ans = (ans + b.p[i][j]) %mod ;
        cout<<ans<<endl ;
    }
    return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值