题目:垒骰子
赌圣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>, 不能通过工程设置而省略常用头文件。
赌圣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;
}