[蓝桥杯2015初赛]垒骰子

[蓝桥杯2015初赛]垒骰子

[蓝桥杯2015初赛]垒骰子

题目大意:

给你n个骰子,给你m组不能贴在一起的面,问你把这n个骰子垒成高度为n的柱体,一共有多少种方案?

题目分析:

  • 首先,不能贴近的面是肯定不能在一起的,我们只需要每次放骰子时不把不能贴近的面放一块儿就行,也就是每个顶面,都可以再放上与它不冲突的面,最后顶面一共会出现6中情况,我们对顶面的6种情况进行dp。
  • dp[i][j]代表的就是高度为i时,顶面为j的方案数,可知
    dp[i][j]=i-1层中所有与j的反面不冲突的面相加,不管i-1层的顶面时什么,只要不与j的反面相冲突即可加入。
  • 由于n的大小有1e9,所以这道题必定要在时间复杂度优化上下功夫,这里可以看出,给你的每个面的反面都是确定的,且冲突的面都是确定的,那么状态转移是不是线性的呢?是线性的,每次都做的是一样的操作,所以我们采用矩阵快速幂优化dp
  • 不了解矩阵快速幂的同学可以先去学学

代码如下

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n,m;
int t[7]={0,4,5,6,1,2,3};
struct node {
 
    ll v[7][7];
}first;
void init(){
 
         for(int i=1;i<7;i++)
           for(int j=1;j<7;j++)
               first.v[i][j]=1;
}
 
node mul(node x,node y){
 
  node t;
  for(int i=1;i<7;i++)
        for(int j=1;j<7;j++)
        {
             t.v[i][j]=0;
             for(int k=1;k<7;k++){
 
                t.v[i][j]+=(x.v[i][k]*y.v[k][j]%mod);
                t.v[i][j]%=mod;
             }
        }
       return t;
}
 
node  mul1(node x,node y)
{
    node t;
    for(int i=1;i<=1;i++)
        for(int j=1;j<7;j++)
    {
        t.v[i][j]=0;
        for(int k=1;k<7;k++)
        {
          t.v[i][j]+=(x.v[i][k]*y.v[k][j]%mod);
                t.v[i][j]%=mod;
        }
    }
     return t;
}
node quick_mi(int k){
 
    node tem;
     for(int i=1;i<7;i++)
     for(int j=1;j<7;j++){
        if(i==j)
           tem.v[i][j]=1;
         else
          tem.v[i][j]=0;
     }
     while(k){
 
        if(k&1){
            tem=mul(tem,first);
        }
     first=mul(first,first);
       k/=2;
     }
     return tem;
}
ll quick_mi1(ll x,int n)
{
    ll tot=1;
    while(n)
    {
        if(n&1)
            tot=tot*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return tot;
}
 
 
int main(){
 
      ios::sync_with_stdio(false);
         cin.tie(0);
         while(cin>>n>>m){
            init();
            while(m--){
                int a,b;
                cin>>a>>b;
               first.v[t[a]][b]=0;
               first.v[t[b]][a]=0;
            }
          node book;
          ll sum=0;
          for(int i=1;i<7;i++)
             book.v[1][i]=1;
         node ans=quick_mi(n-1);
            ans=mul1(book,ans);
            for(int i=1;i<7;i++)
                 sum=(sum+ans.v[1][i])%mod;
            ll x=quick_mi1(4,n);
            sum=sum*x%mod;
            cout<<sum<<endl;
         }
    return 0;
}

有问题的话,可以在下方评论哦

共勉

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值