P2139 小Z的掷骰游戏

Luogu 链接

题意

题目描述

小 Z 得到了一个神奇的骰子(如下图所示)。

这个骰子有以下神奇之处:

  • 它只能往 \(4\)\(5\)\(6\) 三个方向翻滚。
  • 当它翻滚时会导致它下落时,它才会翻滚;当有多个方向可以翻滚时,它会往数字最大的面的方向翻滚。
  • 这种骰子翻滚恰好 \(90^\circ\) 后会竖直下落,当落到平面或另一个骰子上时停下来,然后继续翻滚和下落的过程。

现在小 Z 抛了 \(n\) 个骰子(每次抛的位置都相同,且是竖直抛下),并给出每次抛骰子的上面与前面的数字,他想知道抛完后从上方看每个数字分别出现了几次。


输入格式

多测,第一行一个正整数 \(T\),表示有 \(T\) 组数据。

每组数据第一行一个正整数 \(n\),含义见题目描述


输出格式

对于每组数据仅输出一行,分别为结束后从上方看 \(1\)\(6\) 的个数。

思路

显然每次骰子至多有两个方向可翻滚,所以我们可以记录对于每种情况,其最大面和次大面的方向,以及翻滚后骰子上面及前面的数字,这样就可以不断转移了。

当翻滚后的坐标上骰子的高度是否小于当前坐标上骰子的高度,骰子才能翻滚,所以需要记录每个坐标上骰子的个数(即高度)。为了记录答案,还需要记录每个坐标上最上面的骰子的上面是什么数字。

完成上述操作后,这道题就十分好做了。

为了便于读者理解对于每种情况是如何翻滚的,我对它们都一一画了图,限于篇幅,这里不再展示,而是放在我的另一篇文章里。

程序

AC 记录

#include<cstdlib>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<cmath>
#include<iomanip>
#include<string>
#include<stack>
#define re register
#define uint unsigned int
#define ll long long
#define ull unsigned long long
#define vl __int128
#define ld long double
#define LL 2e18
#define INT 1e9
#define INF 0x3f3f3f3f
#define lb(x) (x&(-x))
#ifdef __linux__
#define gc getchar_unlocked
#define pc putchar_unlocked
#else
#define gc _getchar_nolock
#define pc _putchar_nolock
#endif
int T=1;
using namespace std;
inline bool blank(const char x){return !(x^32)||!(x^10)||!(x^13)||!(x^9);}
template<typename Tp>inline void read(Tp &x){x=0;re bool z=true;re char a=gc();for(;!isdigit(a);a=gc())if(a=='-')z=false;for(;isdigit(a);a=gc())x=(x<<1)+(x<<3)+(a^48);x=(z?x:~x+1);}
inline void read(double &x){x=0.0;re bool z=true;re double y=0.1;re char a=gc();for(;!isdigit(a);a=gc())if(a=='-')z=false;for(;isdigit(a);a=gc())x=x*10+(a^48);if(a!='.')return x=z?x:-x,void();for(a=gc();isdigit(a);a=gc(),y/=10)x+=y*(a^48);x=(z?x:-x);}
inline void read(ld &x){x=0.0;re bool z=true;re ld y=0.1;re char a=gc();for(;!isdigit(a);a=gc())if(a=='-')z=false;for(;isdigit(a);a=gc())x=x*10+(a^48);if(a!='.')return x=z?x:-x,void();for(a=gc();isdigit(a);a=gc(),y/=10)x+=y*(a^48);x=(z?x:-x);}
inline void read(char &x){for(x=gc();blank(x)&&(x^-1);x=gc());}
inline void read(char *x){re char a=gc();for(;blank(a)&&(a^-1);a=gc());for(;!blank(a)&&(a^-1);a=gc())*x++=a;*x=0;}
inline void read(string &x){x="";re char a=gc();for(;blank(a)&&(a^-1);a=gc());for(;!blank(a)&&(a^-1);a=gc())x+=a;}
template<typename T,typename ...Tp>inline void read(T &x,Tp &...y){read(x),read(y...);}
template<typename T>inline void read(T *begin,T *end){re T *i;if(begin<end)for(i=begin;i<end;++i)read(*i);else for(i=begin-1;i>=end;--i)read(*i);}
template<typename Tp>inline void write(Tp x){if(!x)return pc(48),void();if(x<0)pc('-'),x=~x+1;re int len=0;re char tmp[64];for(;x;x/=10)tmp[++len]=x%10+48;while(len)pc(tmp[len--]);}
inline void write(const double x){re int a=6;re double b=x,c=b;if(b<0)pc('-'),b=-b,c=-c;re double y=5*powl(10,-a-1);b+=y,c+=y;re int len=0;re char tmp[64];if(b<1)pc(48);else for(;b>=1;b/=10)tmp[++len]=floor(b)-floor(b/10)*10+48;while(len)pc(tmp[len--]);pc('.');for(c*=10;a;a--,c*=10)pc(floor(c)-floor(c/10)*10+48);}
inline void write(const ld x){re int a=6;re ld b=x,c=b;if(b<0)pc('-'),b=-b,c=-c;re ld y=5*powl(10,-a-1);b+=y,c+=y;re int len=0;re char tmp[64];if(b<1)pc(48);else for(;b>=1;b/=10)tmp[++len]=floor(b)-floor(b/10)*10+48;while(len)pc(tmp[len--]);pc('.');for(c*=10;a;a--,c*=10)pc(floor(c)-floor(c/10)*10+48);}
inline void write(const pair<int,double>x){re int a=x.first;if(a<7){re double b=x.second,c=b;if(b<0)pc('-'),b=-b,c=-c;re double y=5*powl(10,-a-1);b+=y,c+=y;re int len=0;re char tmp[64];if(b<1)pc(48);else for(;b>=1;b/=10)tmp[++len]=floor(b)-floor(b/10)*10+48;while(len)pc(tmp[len--]);a&&(pc('.'));for(c*=10;a;a--,c*=10)pc(floor(c)-floor(c/10)*10+48);}else printf("%.*lf",a,x.second);}
inline void write(const pair<int,ld>x){re int a=x.first;if(a<7){re ld b=x.second,c=b;if(b<0)pc('-'),b=-b,c=-c;re ld y=5*powl(10,-a-1);b+=y,c+=y;re int len=0;re char tmp[64];if(b<1)pc(48);else for(;b>=1;b/=10)tmp[++len]=floor(b)-floor(b/10)*10+48;while(len)pc(tmp[len--]);a&&(pc('.'));for(c*=10;a;a--,c*=10)pc(floor(c)-floor(c/10)*10+48);}else printf("%.*Lf",a,x.second);}
inline void write(const char x){pc(x);}
inline void write(const bool x){pc(x?49:48);}
inline void write(char *x){fputs(x,stdout);}
inline void write(const char *x){fputs(x,stdout);}
inline void write(const string &x){fputs(x.c_str(),stdout);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x),write(y...);}
template<typename T>inline void write(T *begin,T *end,const char c=' '){re T *i;for(i=begin;i<end;++i)write(*i,c);}
template<typename T>inline void init(T *begin,T *end,const T& val=T()){re T* i;for(i=begin;i<end;++i)*i=val;}
template<typename T>inline T max(T *begin,T *end){re T *ans,*i;for(i=begin;i<end;++i)if(i==begin||*ans<*i)ans=i;return *ans;}
template<typename T>inline T min(T *begin,T *end){re T *ans,*i;for(i=begin;i<end;++i)if(i==begin||*i<*ans)ans=i;return *ans;}
template<typename T>inline T calc_sum(T *begin,T *end,const T& val=T()){re T ans=val,*i;for(i=begin;i<end;++i)ans+=*i;return ans;}
template<typename T>inline bool is_equal(T *begin,T *end,const T& val=T()){re T *i;for(i=begin;i<end;++i)if(*i!=val)return false;return true;} //模板,无需在意 

ll mod=0;
const int MAXN=200;
const int N=MAXN+10;
//#define DEBUG
//#define more_text

int n,
	up,front; //up:上面的数 front:前面的数 

int h[N][N],on[N][N],ans[7], //h[i][j]: 坐标 (i,j) 上有几个骰子
                             //on[i][j]: 坐标 (i,j) 上最上方骰子上面的数
							 //ans[i]: i 出现了几次 
	dir[2],U[2],F[2],x,y,tx,ty, //数组下标为 0 表示最大面,为 1 表示次大面
	                            //dir[]:滚动方向
								//U[]:滚动后上面的数字
								//F[]:滚动后前面的数字 
								//(x,y): 当前坐标 (tx,ty): 滚动后的坐标 
	d[5][2]={{0,0},{0,-1},{-1,0},{0,1},{1,0}}; //增量数组 下标 1~4 分别为 向前面、 向左面、向后面、向右面 

void clear(){
	memset(h,0,sizeof(h));
	memset(on,0,sizeof(on));
	memset(ans,0,sizeof(ans)); //多测须清空 
}

void init(){
	//当前前面为 front,上面为 up 时,dir[]、U[]、F[] 的值 
	if(front==1){
		if(up==2)dir[0]=3,dir[1]=4,U[0]=1,F[0]=5,U[1]=3,F[1]=1;
		if(up==3)dir[0]=3,dir[1]=2,U[0]=1,F[0]=4,U[1]=2,F[1]=1;
		if(up==4)dir[0]=3,dir[1]=4,U[0]=1,F[0]=3,U[1]=2,F[1]=1;
		if(up==5)dir[0]=3,dir[1]=2,U[0]=1,F[0]=2,U[1]=3,F[1]=1;
	}
	if(front==2){ 
		if(up==1)dir[0]=3,dir[1]=2,U[0]=2,F[0]=6,U[1]=3,F[1]=2;
		if(up==3)dir[0]=4,dir[1]=3,U[0]=1,F[0]=2,U[1]=2,F[1]=4;
		if(up==4)dir[0]=2,dir[1]=3,U[0]=1,F[0]=2,U[1]=2,F[1]=3;
		if(up==6)dir[0]=3,dir[1]=4,U[0]=2,F[0]=1,U[1]=3,F[1]=2;
	}
	if(front==3){ 
		if(up==1)dir[0]=4,dir[1]=3,U[0]=2,F[0]=3,F[1]=6,U[1]=3;
		if(up==2)dir[0]=2,dir[1]=3,U[0]=1,F[0]=3,F[1]=5,U[1]=3;
		if(up==5)dir[0]=4,dir[1]=3,U[0]=1,F[0]=3,F[1]=2,U[1]=3;
		if(up==6)dir[0]=2,dir[1]=3,U[0]=2,F[0]=3,F[1]=1,U[1]=3;
	}
	if(front==4){
		if(up==1)dir[0]=2,dir[1]=1,U[0]=2,F[0]=4,U[1]=3,F[1]=1;
		if(up==2)dir[0]=4,dir[1]=1,U[0]=1,F[0]=4,U[1]=3,F[1]=2;
		if(up==5)dir[0]=2,dir[1]=1,U[0]=1,F[0]=4,U[1]=3,F[1]=5;
		if(up==6)dir[0]=4,dir[1]=1,U[0]=2,F[0]=4,U[1]=3,F[1]=6;
	}
	if(front==5){ 
		if(up==1)dir[0]=1,dir[1]=4,U[0]=2,F[0]=1,U[1]=3,F[1]=5;
		if(up==3)dir[0]=2,dir[1]=1,U[0]=1,F[0]=5,U[1]=2,F[1]=3;
		if(up==4)dir[0]=4,dir[1]=1,U[0]=1,F[0]=5,U[1]=2,F[1]=4;
		if(up==6)dir[0]=1,dir[1]=2,U[0]=2,F[0]=6,U[1]=3,F[1]=5;
	}
	if(front==6){
		if(up==2)dir[0]=1,dir[1]=2,U[0]=1,F[0]=2,U[1]=3,F[1]=6;
		if(up==3)dir[0]=1,dir[1]=4,U[0]=1,F[0]=3,U[1]=2,F[1]=6;
		if(up==4)dir[0]=1,dir[1]=2,U[0]=1,F[0]=4,U[1]=2,F[1]=6;
		if(up==5)dir[0]=1,dir[1]=4,U[0]=1,F[0]=5,U[1]=3,F[1]=6;
	}
}

void move_dice(){
	//滚骰子 
	init();
	
	tx=x+d[dir[0]][0],ty=y+d[dir[0]][1]; //最大面 
	if(h[tx][ty]<h[x][y]){ //能滚过去就滚 
		x=tx,y=ty,
		up=U[0],front=F[0];
		
		move_dice();
		return;
	}
	
	tx=x+d[dir[1]][0],ty=y+d[dir[1]][1]; //次大面 
	if(h[tx][ty]<h[x][y]){
		x=tx,y=ty,
		up=U[1],front=F[1];
		
		move_dice();
		return;
	}
	
	++h[x][y];
	--ans[on[x][y]],++ans[up];
	on[x][y]=up; //覆盖原先的值 
}

void solve(int step){
	while(scanf("%d",&n)!=EOF){
		clear();
		
		for(int i=0;i<n;++i){
			read(up,front);
			
			x=y=100;
			move_dice();
		}
		
		write(ans+1,ans+7);
		write('\n');
	}
}
/*
Input:

Output:

Outline:

*/
int main(){ //模板,无需在意 
	#ifdef DEBUG
	freopen("test.in","r",stdin);freopen("test.out","w",stdout);
	#endif
	#ifdef more_text
	read(T);
	#endif
	for(int i=0;i<T;++i)solve(i);
	#ifdef DEBUG
	fclose(stdin);fclose(stdout);
	#endif
	return 0;
}
posted @ 2025-03-09 09:59  LXcjh4998  阅读(28)  评论(0)    收藏  举报