举火燎天

来源:互联网 发布:linux u盘挂载乱码 编辑:程序博客网 时间:2024/05/01 17:20

举火燎天


问题描述

征夷王将越南(南夷)攻下来之后,决定用 N 个火炬摆成一个圆圈,围住越南的都城,以举火燎天宣告自己的胜利。
N 个火炬的位置已经固定了,但是,每个火炬的颜色都没定,总共有 M 种颜色的火炬。
为了显示我们中华文化的博大精深,征夷王决定,相邻的火炬的颜色不能相同。
现在征夷王想知道,满足他要求的方案有多少个。
由于火炬的位置已经固定,所以即便旋转翻转之后两种方案相同也视作不同方案。


输入

输入文件名为Lights.in。
输入一行两个正整数 NM,意义如上所述。


输出

输出文件名为Lights.out。
输出一行一个正整数,代表方案总数。


输入样例

3 4


输出样例

24


数据范围

对于 100% 的数据,1<=N,M<=100


Solution

f[i][1] 表示第 i 个火炬与第 1 个火炬颜色相同的方案个数,而 f[i][0] 表示第 i 个火炬与第 1 个火炬颜色不同的方案个数。

f[1][0]=0f[1][1]=m

f[i][0]=f[i1][1](m1)+f[i1][0](m2)

f[i][1]=f[i1][0]


Code

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define LL long long#define MOD 100000000#define Max(x,y) ((x)>(y)?(x):(y))struct bign{    LL s[100],len;    bign(){        memset(s,0,sizeof s);        len=1;    }    bign operator = (const LL num){        s[1]=num;len=1;        return *this;    }    bign operator * (const LL num){        bign c;c.len=len+1;        for(LL i=1;i<=len;i++){            c.s[i+1]=(c.s[i]+s[i]*num)/MOD;            c.s[i]=(c.s[i]+s[i]*num)%MOD;        }        while(!c.s[c.len]&&c.len>1)c.len--;        return c;    }    bign operator + (const bign &num){        bign c;c.len=Max(len,num.len);        for(LL i=1;i<=c.len;i++){            c.s[i+1]=(c.s[i]+s[i]+num.s[i])/MOD;            c.s[i]=(c.s[i]+s[i]+num.s[i])%MOD;        }        if(c.s[c.len+1])c.len++;        return c;    }    void out(){        for(LL i=len;i>=1;i--){            if(len==i)printf("%lld",s[len]);            else printf("%08lld",s[len]);        }    }};LL n,m;bign f[110][2];int main(){    freopen("Lights.in","r",stdin);    freopen("Lights.out","w",stdout);    scanf("%lld%lld",&n,&m);    if(n==1){        printf("%lld\n",m);        return 0;    }    else if(n==2){        LL ans=m*(m-1);        printf("%lld\n",ans);        return 0;    }    else{        f[1][1]=m;f[0][0]=0;        for(int i=2;i<=n;i++){            f[i][1]=f[i-1][0];            f[i][0]=f[i-1][0]*(m-2)+f[i-1][1]*(m-1);        }        f[n][0].out();    }    return 0;}
1 0