LA2029 状压dp

Mr. Richards, an enthusiastic mathematician, is spending his holiday in Shanghai. He is so crazy about his study that he may associate anything with mathematical problems. According to his schedule, he should visit the Museum today. But after getting up, he was in a daze in the hotel, thinking deeply about a coloration problem. Yesterday, when he took a walk in the nightfall, the slabs of stone paved on the piazza fascinated him. He has associated those stones with a combinatorial problem.

The shape of those slabs of stone is equilateral triangle whose side length is 1 meter. But if Mr. Richards arranges 4 slabs of stone, as Fig.1 below shows, those stones may form a larger equilateral triangle whose side length is 2 meters. He designates those stones with the numbers 1 to 4 first, then he tries to use three different colors - blue, green and red - to color those stones. In such a triangle, the contiguous stones are required not to be painted with the same color. He asks himself to find out the number of the coloration methods. Since he is a learned person in combinatorial theory, it's not a difficult problem for him. Soon he works out the answer, 24. You know, because of the marks on those stones, they should not be regarded as the same ones.

\epsfbox{p2029a.eps}

Fig.1 The colored slabs of stone

Arranging for more slabs of stone to form a larger triangle, and using more colors, the coloration problem will be much more complex. For example, arranging 9 slabs of stone, as Fig.2 below shows, Mr. Richards has to form a triangle whose side length is 3 meters. Using 5 colors to paint on those stones, the answer will be an enormous number. Without a computer, he could not tell the result exactly, although he knows clearly how to account the coloration methods. So you are required to write a program to tell him the exact answer.

\epsfbox{p2029b.eps}

Fig.2 The triangle whose side length is 3 meters

Input 

The input file may contain several data sets. Each data set consists of two integers l (0$ \le$l$ \le$6)and c (1$ \le$c$ \le$4). The first integer l represents the side length of the triangle formed by slabs of stone. The second integer c represents the number of the kinds of the colors. The input file is terminated by l = 0.

Output 

For each data set, compute s, the number of the coloration methods without any two contiguous stones painted with the same color. If the colors given are insufficient to paint the slabs of stone, the answer should be 0. Output your answer as a single integer on a line by itself.


Note: You are required to tell him the exact answers, not the floating-point values.

Sample Input 

2 3 
3 3
0 0

Sample Output 

24 
528

此题如果按常规方法做,那么状态数将达到4^11,这样做显然会TLE。

我们观察第i-1的奇数块可能会与第i行的偶数块发生冲突,利用这个性质,我们将一行拆成两部分,奇数块和偶数块,因此对于第i行的偶数块是通过第i-1行的奇数块dp而来的,但第i行的奇数块不能与第i行的偶数块冲突,我们发现第i行的奇数块比偶数块多1块,我们只要判断奇数块的前i块和后i块与偶数块是否冲突即可。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;

int p[10];
ll dp[2][5000];
int n,m;
bool check(int i,int j,int len){
    while(len--){
        if(i%m==j%m) return false;
        i/=m,j/=m;
    }
    return true;
}
int main()
{
    while(cin>>n>>m,n){
        p[0]=1;
        for(int i=1;i<10;i++) p[i]=p[i-1]*m; //m^i
        memset(dp,0,sizeof dp);
        for(int i=0;i<m;i++) dp[0][i]=1; //初始化第0行奇数块
        for(int i=1;i<n;i++){ //第i行拆成2行
            memset(dp[1],0,sizeof dp[1]);
            for(int j=0;j<p[i];j++) //第i行偶数块有i个
                for(int k=0;k<p[i];k++) //第i-1行奇数块有i个
                    if(check(j,k,i)) dp[1][j]+=dp[0][k];
            memset(dp[0],0,sizeof dp[0]);
            for(int j=0;j<p[i+1];j++) //第i行奇数块有i+1个
                for(int k=0;k<p[i];k++) //第i行偶数块有i个
                    //奇数块前i个和末i个不与偶数块冲突
                    if(check(j/m,k,i)&&check(j%p[i],k,i))
                        dp[0][j]+=dp[1][k];
        }
        ll ans=0;
        for(int i=0;i<p[n];i++)
            ans+=dp[0][i];
        cout<<ans<<endl;
    }
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值