经典题型。如果列数较少,就能用我们熟知的状态压缩DP解决。但现在列数有231。考虑到相邻两列之间状态转移规则是相同的,我们可以用矩阵表示这种转移规则,而最后的结果就是求这个转移矩阵的n次幂的左上角元素。


/*************************************************************************
Author: WHU_GCC
Created Time: 2007-10-6 11:05:55
File Name: pku3420.cpp
Description: 
***********************************************************************
*/

#include 
<iostream>
using namespace std;
#define out(x) (cout<<#x<<": "<<x<<endl)
const int maxint=0x7FFFFFFF;
typedef 
long long int64;
const int64 maxint64 = 0x7FFFFFFFFFFFFFFFLL;
template
<class T>void show(T a, int n){for(int i=0; i<n; ++i) cout<<a[i]<<' '; cout<<endl;}
template
<class T>void show(T a, int r, int l){for(int i=0; i<r; ++i)show(a[i],l);cout<<endl;}

int g[16][16];
int M;

void dfs(int old_state, int now, int new_state)
{
    
if (now > 3)
    
{
        g[old_state][new_state]
++;
        
return;
    }

    
if (old_state & (1 << now))
        dfs(old_state, now 
+ 1, new_state);
    
if (now <= 2)
    
{
        
if ((old_state & (1 << now)) == 0 && (old_state & (1 << (now + 1))) == 0)
            dfs(old_state, now 
+ 2, new_state);
    }

    
if ((old_state & (1 << now)) == 0)
        dfs(old_state, now 
+ 1, new_state | (1 << now));
}


void mul(int a[16][16], int b[16][16], int c[16][16])
{
    
for (int i = 0; i < 16; i++)
        
for (int j = 0; j < 16; j++)
        
{
            c[i][j] 
= 0;
            
for (int k = 0; k < 16; k++)
                c[i][j] 
+= a[i][k] * b[k][j];
            c[i][j] 
%= M;
        }

}


int calc(int n)
{
    
int p[16][16];
    memcpy(p, g, 
sizeof(p));
    
    
int ans[16][16], tmp[16][16];
    memset(ans, 
0sizeof(ans));
    
for (int i = 0; i < 16; i++)
        ans[i][i] 
= 1;

    
while (n)
    
{
        
if (n & 1)
        
{
            mul(ans, p, tmp);
            memcpy(ans, tmp, 
sizeof(tmp));
        }

        n 
>>= 1;
        mul(p, p, tmp);
        memcpy(p, tmp, 
sizeof(tmp));
    }

    
return ans[0][0];
}


int main()
{
    memset(g, 
0sizeof(g));
    
for (int i = 0; i < 16; i++)
        dfs(i, 
00);
    
    
int n;
    
while (scanf("%d%d"&n, &M), n + M != 0)
    
{
        printf(
"%d\n", calc(n));
    }

    
return 0;
}
posted on 2007-10-08 09:19 Felicia 阅读(1076) 评论(0)  编辑 收藏 引用 所属分类: 动态规划

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理