HDU 3893 Drawing Pictures

/*
题目的要求是用1-6六种颜色排成一列 
而且必须对称。相邻不同色。不出现123456 
 
n为偶数的时候必然无解, 
因为最中心两个无法满足相邻不同色的要求 
 
对于n奇数的情况因为是对称考虑前n/2+1的部分 
这部分必然满足相邻不同色,不出现123456 
同时不出现654321(翻转到另一侧不合法) 
求排列的数量

题解:构造DP来解
D[i][s] 表示长度为i时以s结尾的方案数
显然ans=sum(D[n][s])(s=1,2,3,4,5,6);
构造状态 1,2,3,4,5,6
因为s=1和6由D[i][]转换过来时候要减去以s=65432和s=12345的状态
所以构造状态65432,12345
要得到65432必须从状态6543,以此类推构造654,65
同理1234,123,12;
所以一共14个状态,根据关系写出转移关系,构造矩阵加速求解
*/
#include <iostream>
#include <cmath>
#include <cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstdio>
#include<ctime>
#include<cstring>
using namespace std;
const int SZ=14;
const int MOD=112233;
long long m[14][14]={
{0, 1, 1, 1, 1, 1, 0, 0, 0, 0,-1, 0, 0, 0},
{1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
},init[14][14];
void multiply(long long  m1[][14],long long m2[][14])
{
    long long ret[SZ][SZ];
    for(int i = 0; i < SZ; ++i)
    {
        for(int j = 0; j < SZ; ++j)
        {
            ret[i][j] = 0;
            for(int k = 0; k < SZ; ++k)
            ret[i][j] = (ret[i][j] + ((long long)m1[i][k] * m2[k][j])% MOD) % MOD;
        }
    }
    for(int i = 0; i < SZ; ++i)
    {
        for(int j = 0; j < SZ; ++j)
        {
            m1[i][j]=ret[i][j]%MOD;
        }
    }
}
void solve(int n)
{
    long long k[14][14],g[14][14];
    for(int i=0;i<14;i++)
    {
        for(int j=0;j<14;j++)
        {
            init[i][j]=(i==j?1:0);
            k[i][j]=m[i][j];
        }
    }
    while(n)
    {
        if(n&1)multiply(init,k);
        multiply(k,k);
        n/=2;
    }
    for(int i=0;i<14;i++)
    for(int j=0;j<14;j++)
    {
        if(i<6&&j==0)g[i][j]=1;
        else g[i][j]=0;
    }
        multiply(init,g);
        long long ans=0;
        for(int i = 0; i < 6; ++i)
        {
        ans=(ans+init[i][0]%MOD)%MOD;
        }
        cout<<(ans+MOD)%MOD<<endl;
}
int main()
{

    int n;
  while(scanf("%d",&n)!=EOF)
  {
    if((n&1)==0){puts("0");continue;}
    solve(n/2);
  }
  return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值