【第六届蓝桥杯】垒骰子

题目:垒骰子

赌圣atm晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。
经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!
我们先来规范一下骰子:1 的对面是 4,2 的对面是 5,3 的对面是 6。
假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。 
atm想计算一下有多少种不同的可能的垒骰子方式。
两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。
由于方案数可能过多,请输出模 10^9 + 7 的结果。

不要小看了 atm 的骰子数量哦~

「输入格式」
第一行两个整数 n m
n表示骰子数目
接下来 m 行,每行两个整数 a b ,表示 a 和 b 数字不能紧贴在一起。

「输出格式」
一行一个数,表示答案模 10^9 + 7 的结果。

「样例输入」
2 1
1 2

「样例输出」
544

「数据范围」
对于 30% 的数据:n <= 5
对于 60% 的数据:n <= 100
对于 100% 的数据:0 < n <= 10^9, m <= 36

资源约定:
峰值内存消耗 < 256M
CPU消耗  < 2000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。


这题难度较大,我也做不出来,也搜不到完全正确的答案。这里就贴一些别人的思路做参考吧。

C++代码:

//存在问题 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include <vector>
using namespace std;
typedef  unsigned int uint;  
typedef uint SizeType;                      // ...表示大小   
typedef uint IndexType;                     // ...表示下标   
typedef long long ValueType;                // ...表示值   
typedef vector< ValueType > RowType;      // ...表示矩阵的一行   
typedef vector< RowType > ContainerType;  // ...矩阵容器   
#define MOD 1000000007  
  
// ...矩阵类的实现   
class Matrix{  
    public:  
        Matrix( SizeType Row, SizeType Col, ValueType Init_Val=0 ):m_row(Row),m_col(Col){  
            m_mtx = new ContainerType( m_row, RowType(m_col,Init_Val) );  
        }  
        Matrix( const Matrix& Copyright ):m_row(Copyright.m_row),m_col(Copyright.m_col){  
            m_mtx = new ContainerType( *Copyright.m_mtx );  
        }  
        inline SizeType GetRow()const{ return m_row; }  
        inline SizeType GetCol()const{ return m_col; }  
          
        // ...矩阵赋值   
        const Matrix& operator=( const Matrix& right ){  
            *m_mtx = *right.m_mtx;  
            m_row = right.m_row;  
            m_col = right.m_col;  
        }  
          
        // ...获取矩阵中第rI行cI列的元素   
        inline const ValueType& operator()( IndexType rI,IndexType cI )const{  
            return (*m_mtx)[rI][cI];  
        }  
        inline ValueType& operator()( IndexType rI, IndexType cI){  
            return const_cast<ValueType&>( static_cast<const Matrix&>(*this)(rI,cI) );  
        }  
          
        // ...获得一个n阶的单位矩阵  
        static Matrix GetIdentityMatrix( SizeType nDimension )   
        {  
            Matrix I( nDimension,nDimension,0);  
            for( IndexType i = 0; i < nDimension; ++i)  
                I(i,i) = 1;  
            return I;  
        }  
          
        // ...矩阵乘法   
        const Matrix operator*( const Matrix& right )const{  
            Matrix Res( m_row, right.m_col,0);  
            if( m_col == right.m_row ){  
                const Matrix& left = *this;  
                for( IndexType i = 0; i < m_row; ++i)      
                    for( IndexType j = 0; j < right.m_col; ++j)  
                        for( IndexType t = 0; t < m_col; ++t )  
                            Res(i,j) = (Res(i,j)+left(i,t)*right(t,j)%MOD)%MOD;  
            }  
            return Res;  
        }  
        const Matrix& operator*=( const Matrix& right ){return *this = (*this)*right;}  
          
        // ...矩阵快速幂  
        const Matrix operator^( uint N ) const{  
            Matrix Res = GetIdentityMatrix( m_row ),t = *this;  
            while( N ){  
                if( N&1 ) Res*=t;  
                t*=t;  
                N>>=1;  
            }  
            return Res;  
        }  
        const Matrix& operator^=(uint N){ return *this = (*this)^N; }  
    protected:  
        SizeType m_row, m_col;  // ...行数, 列数  
        ContainerType *m_mtx;   // ...容器   
};  
  
// ...常数快速幂  
ValueType Pow( ValueType a, uint N ) {  
    ValueType Res = 1;  
    while( N ){  
        if( N&1 ) Res=Res*a%MOD;  
        a=a*a%MOD;  
        N>>=1;  
    }  
    return Res;  
}  
int main(int argc, char** argv) {  
    Matrix Complict(6,6,1); // ...冲突组合记录  
    Matrix Count( 1,6,1 );// ...总数记录  
    const IndexType Parner[6] = {3,4,5,0,1,2}; // ...反面记录   
    uint N, M, s1, s2;  
    cin >> N >> M;   
    for( uint i = 0; i < M; ++i){  
        cin >> s1 >> s2;  
        Complict( Parner[s1],s2 ) = Complict( Parner[s2],s1 ) = 0;  
    }  
    Complict^=(N-1);  
    Count*=Complict;  
    ValueType sum = 0;  
    for( IndexType i = 0; i < Count.GetCol(); ++i)  
        sum = (sum+Count(0,i))%MOD;  
    cout << sum*Pow(4,N)%MOD;  
    return 0;  
}  

//存在问题 
#include <iostream>
using namespace std;

const int Size = 7;
const long long Max = 10e9+7;

class Matrix
{
	friend ostream& operator<<(ostream& out , const Matrix& obj);
	public:
	long long matrix[Size][Size];
	Matrix(long long initialValue = 0){	
		int i , j;
		for(i = 0 ; i < 6 ; ++i){
			for(j = 0 ; j < 6 ; ++j){
				matrix[i][j] = initialValue;
			}
		}
	}
	static Matrix multiply(const  Matrix& src1 , const Matrix& src2){
		Matrix rst;
		int i , j , k;
		for(i = 0 ; i < 6 ; ++i){
			for(j = 0 ; j < 6 ; ++j){
				for(k = 0 ; k < 6 ; ++k){
					rst.matrix[i][j] += src1.matrix[i][k]*src2.matrix[k][j];
				}
			}
		}
		return rst;
	}
	static Matrix matrixPower(Matrix src , int times){
		Matrix rst;
		int i;
		for(i = 0 ; i < 6 ; ++i){
			rst.matrix[i][i] = 1;
		}
		while(times){
			if(times&1){
				rst = multiply(rst , src);
			}
			src = multiply(src , src);
			times >>= 1;
		}
		return rst;
	}
};

ostream& operator<<(ostream& out , const Matrix& obj){
	int i , j;
	for(i = 0 ; i < 6 ; ++i){
		for(j = 0 ; j < 6 ; ++j){
			out << obj.matrix[i][j] << " ";
		}
		out << endl;
	}
	return out;
}

long long intPower(long long n , long long times){
	long long rst = 1;
	while(times){
		if(times&1){
			rst *= n;
			rst %= Max;
		}
		n *= n;
		times >>= 1;
	}
	return rst;
}

int main(){
	int n , m;
	cin >> n >> m;
	Matrix connection(1);
	int a , b;
	while(m--){
		cin >> a >> b;
		connection.matrix[a][b] = connection.matrix[b][a] = 0;
	}
	Matrix grond;
	int i;
	for(i = 0 ; i < 6 ; ++i){
		grond.matrix[0][i] = 1;
	}
	grond = Matrix::multiply(grond , Matrix::matrixPower(connection , n-1));
	long long rst = 0;
	for(i = 0 ; i < 6 ; ++i){
		rst += grond.matrix[0][i];
		rst %= Max;
	} 
	rst = (rst*(intPower(4 , n)%Max))%Max;
	cout << rst << endl; 
	return 0;
}

//dp代码:
#include <iostream>  
#include <cstring> 
#define CLR(a, b) memset(a, (b), sizeof(a))  
#define ll o<<1  
#define rr o<<1|1  
#define fi first  
#define se second  
using namespace std;  
typedef long long LL;  
const int MOD = 1e9+7;  
void add(LL &x, LL y) {x += y; x %= MOD;}  
int a[7] = {0, 4, 5, 6, 1, 2, 3};  
LL dp[2][7];  
bool Map[7][7];  
LL pow_mod(LL a, int n)  
{  
    LL ans = 1LL;  
    while(n)  
    {  
        if(n & 1)  
            ans = ans * a % MOD;  
        a = a * a % MOD;  
        n >>= 1;  
    }  
    return ans;  
}  
int main()  
{  
    int n, m; 
	scanf("%d%d", &n, &m);  
    CLR(Map, false);  
    while(m--) {  
        int u, v; 
		scanf("%d%d", &u, &v);  
        Map[u][v] = Map[v][u] = true;  
    }  
    for(int i = 1; i <= 6; i++) dp[1&1][i] = 1LL;  
    for(int i = 2; i <= n; i++) {  
        for(int j = 1; j <= 6; j++) {  
            dp[i&1][j] = 0LL;  
            for(int k = 1; k <= 6; k++)  
                if(!Map[a[j]][k]) add(dp[i&1][j], dp[(i-1)&1][k]);  
        }  
    }  
    LL ans = 0;  
    for(int i = 1; i <= 6; i++) add(ans, dp[n&1][i]);  
    cout << ans * pow_mod(4, n) % MOD << endl;  
    return 0;  
}  

//矩阵加速代码:
#include <iostream>  
#include <cstring>  
#define CLR(a, b) memset(a, (b), sizeof(a))  
#define ll o<<1  
#define rr o<<1|1  
#define fi first  
#define se second  
using namespace std;  
typedef long long LL;  
const int MOD = 1e9+7;  
void add(LL &x, LL y) {x += y; x %= MOD;}  
int a[7] = {0, 4, 5, 6, 1, 2, 3};  
struct Matrix {  
    LL a[7][7];  
};  
Matrix multi(Matrix x, Matrix y)  
{  
    Matrix z; CLR(z.a, 0);  
    for(int i = 1; i <= 6; i++)  
    {  
        for(int k = 1; k <= 6; k++)  
        {  
            if(x.a[i][k] == 0) continue;  
            for(int j = 1; j <= 6; j++)  
                add(z.a[i][j], x.a[i][k] * y.a[k][j] % MOD);  
        }  
    }  
    return z;  
}  
Matrix res, ori;  
Matrix Pow(int n)  
{  
    while(n)  
    {  
        if(n & 1)  
            res = multi(res, ori);  
        ori = multi(ori, ori);  
        n >>= 1;  
    }  
}  
bool Map[7][7];  
LL pow_mod(LL a, int n)  
{  
    LL ans = 1LL;  
    while(n)  
    {  
        if(n & 1)  
            ans = ans * a % MOD;  
        a = a * a % MOD;  
        n >>= 1;  
    }  
    return ans;  
}  
int main()  
{  
    int n, m; scanf("%d%d", &n, &m);  
    CLR(Map, false);  
    while(m--) {  
        int u, v; scanf("%d%d", &u, &v);  
        Map[u][v] = Map[v][u] = true;  
    }  
    CLR(ori.a, 0LL); CLR(res.a, 0LL);  
    for(int i = 1; i <= 6; i++) {  
        res.a[i][i] = 1LL;  
        for(int j = 1; j <= 6; j++) if(!Map[i][a[j]])  
            ori.a[i][j]++;  
    } Pow(n-1);  
    LL ans = 0;  
    for(int i = 1; i <= 6; i++)  
        for(int j = 1; j <= 6; j++)  
            add(ans, res.a[i][j]);  
    cout << ans * pow_mod(4, n) % MOD << endl;  
    return 0;  
}  

//存在问题 
/*作者思路 
这题稍微难一些,而且测试数据规模非常大,所以要做相应的处理,
首先我们考虑题上给的两个筛子的情况,题上给的测试数据中不能相
互碰到的筛子是1,2两个面,所以我们可以这样想:首先第一个筛子
面对我们的数字应该是有6中情况,但是筛子还可以旋转同样可以使该
数字对着我们。所以我们应该找两个面来确定筛子的一种情况,我们
来用上面和前面两个面来看。前面有6种选择,确定前面后上面有4种
选择,所以一个筛子的状态就有24种选择,那么两个就有24X24=576
种,还需要减去1上2下或2上1下两种情况。1为上有4种情况2为下有4
种情况,所以算上2上1下一共应该有4x4x2=32种情况,结果就应该只
有576-32=544种情况。
*/
#include<stdio.h>
#include<math.h>
//做缓存的数组 
int array[100000000] = {0};
int way[24][2] = {
                      {1,2},{1,3},{1,5},{1,6},
                      {2,1},{2,3},{2,4},{2,6},
                      {3,1},{3,2},{3,4},{3,5},
                      {4,2},{4,2},{4,3},{4,6},
                      {5,1},{5,3},{5,4},{5,6},
                      {6,1},{6,2},{6,4},{6,5}
                 };

int checkWay(int n,int up,int m,int check[36][2])
{
    int i;
    int down;
    down = way[n][1]>3?way[n][1]-3:way[n][1]+3;
    for(i = 0 ; i < m ; i++)
    {
        if(check[i][0] == up && check[i][1] == down)
            return 0;
        if(check[i][1] == up && check[i][0] == down)
            return 0;
    }
    return 1;
}

long long f(int n,int up,int m,int check[36][2])
{
    int i;
    long long count = 0;
    if(n == 0)
    {
        return 1;
    }
    for(i = 0 ; i < 24 ;i++)
    {
        if(up == 0)
        {
            count += f(n-1,way[i][1],m,check);
        }
        else
        {
            if(checkWay(i,up,m,check))
            {
                count += f(n-1,way[i][1],m,check);
            }
            else
                continue;
        }
    }
    return count;
}

int main()
{
    int n,m;
    int check[36][2];
    int i,j;
    scanf("%d %d",&n,&m);
    for(i = 0; i < m ;i++)
    {
        scanf("%d %d",&check[i][0],&check[i][1]);
    }
    printf("%I64d",f(n,0,m,check));
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Homilier

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值