垒骰子
资源限制 时间限制:1.0s 内存限制:256.0MB赌圣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
1.暴力递归(递归)上至下
#include<iostream>
#include<stdio.h>
using namespace std;
int op[7];
bool conflict[7][7];
int main(){
op[1]=4;
op[4]=1;
op[2]=5;
op[5]=2;
op[3]=6;
op[6]=3;
int n,m;
int x,y;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
conflict[x][y]=true;
conflict[y][x]=true;
}
long long dp[2][7]; //[第几层][朝上数字] dp[][]:第几层x朝上的可能
//第几层用0和1轮流,因为只涉及到第n层和第n-1层(共两层)
int cnt=0;
for(int up=1;up<=6;up++){ //第一层的六种朝上情况 (初始化)
dp[cnt][up]=1; //up=1时有四种可能(四个侧面)up=2时有四种可能(四个侧面)...
}
for(int level=2;level<=n;level++){
cnt=1-cnt; //第n层时n=1
for(int up2=1;up2<=6;up2++){ //第n层 (可想为第2层)
dp[cnt][up2]=0;
for(int up1=1;up1<=6;up1++){ //第n-1层 (可想为第1层)
if(conflict[op[up2]][up1]) continue;
dp[cnt][up2]=dp[cnt][up2]+dp[1-cnt][up1];
}
}
}
long long sum=0;
for(int up2=1;up2<=6;up2++){
sum+=dp[cnt][up2];
}
//快速幂求n的4次方
long long ans=1;
long long tmp=4;
long long p=n;
while(p!=0){
if(p&1==1) ans=(ans*tmp)%1000000007;
tmp=(tmp*tmp)%1000000007;
p>>=1;
}
printf("%lli",(sum*ans)%1000000007);
return 0;
}
2.动态规划(递推)下至上垒
#include<iostream>
#include<stdio.h>
using namespace std;
int op[7];
bool conflict[7][7];
int main(){
op[1]=4;
op[4]=1;
op[2]=5;
op[5]=2;
op[3]=6;
op[6]=3;
int n,m;
int x,y;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
conflict[x][y]=true;
conflict[y][x]=true;
}
long long dp[2][7]; //[第几层][朝上数字] dp[][]:第几层x朝上的可能
//第几层用0和1轮流,因为只涉及到第n层和第n-1层(共两层)
int cnt=0;
for(int up=1;up<=6;up++){ //第一层的六种朝上情况 (初始化)
dp[cnt][up]=1; //up=1时有四种可能(四个侧面)up=2时有四种可能(四个侧面)...
}
for(int level=2;level<=n;level++){
cnt=1-cnt; //第n层时n=1
for(int up2=1;up2<=6;up2++){ //第n层 (可想为第2层)
dp[cnt][up2]=0;
for(int up1=1;up1<=6;up1++){ //第n-1层 (可想为第1层)
if(conflict[op[up2]][up1]) continue;
dp[cnt][up2]=dp[cnt][up2]+dp[1-cnt][up1];
}
}
}
long long sum=0;
for(int up2=1;up2<=6;up2++){
sum+=dp[cnt][up2];
}
//快速幂求n的4次方
long long ans=1;
long long tmp=4;
long long p=n;
while(p!=0){
if(p&1==1) ans=(ans*tmp)%1000000007;
tmp=(tmp*tmp)%1000000007;
p>>=1;
}
printf("%lli",(sum*ans)%1000000007);
return 0;
}
3、用矩阵(待更新)