[硫化铂]开心消消乐

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[硫化铂]开心消消乐相关的知识,希望对你有一定的参考价值。

开心消消乐

题目概述


题解

首先很容易联想到 Gym 102586J 于是我们自然而然可以想到通过建立一个dfa来处理。
但显然,我们这个dfa怎么建才是关键。

我们观察到我们每次是将三个连续的字符脱水缩合成一个字符,事实上我们每次可以将前面的两个字符当成一个函数,而最后一位当作传入函数的参数。
实际上, 我们发现,我们的每次操作相当于以最后一个数作为参数,将前面的函数不断嵌套。
而我们的函数总共只有四种:不变,交换位置,全赋 0 / 1 0/1 0/1,它们之间的嵌套是具有封闭性的,即无论怎么嵌套都是这四种函数之一。
由于我们每次的操作都是针对一个前缀的,我们不妨记录下我们这些前缀能够构造出上面的哪些函数,记 d p i , j dp_i,j dpi,j表示我们使用长度为 i i i的前缀,可以构造出的函数集合为 j j j
显然,当加入的两个字符确定时,我们函数集合可以有两种变化,一是用 h ( x ) = f ( g ( x ) ) h(x)=f(g(x)) h(x)=f(g(x))的方式,与前面的函数嵌套起来,一是将第一个字符传到前面的函数中,用返回值和后一个字符得到新的函数。
这两种方式得到函数集合的并,就是我们转移到的新函数集合。
我们可以通过这种方式,确定我们转移到的集合。但由于加入的两个字符不是确定的,所以我们还得去枚举新加入的字符。
我们不妨将我们的函数集合就看做dfa上的点,而加入的字符就看做dfa上的边,那我们的整个过程就是在dfa上跑dp。
显然,我们可以先将这个dfa的图预处理出来,然后在上面跑就行了。

时间复杂度 O ( T n ) O\\left(Tn\\right) O(Tn),不过还有个 2 5 2^5 25的常数。

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXM (1<<4)+5
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int mod=1e5+3;
const int inv2=499122177;
const int jzm=2333;
const int zero=2000;
const int n1=2000;
const int M=100000;
const int orG=3,ivG=332748118;
const long double Pi=acos(-1.0);
const double eps=1e-12;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0')if(s=='-')f=-1;s=getchar();
	while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
	x*=f;

template<typename _T>
void print(_T x)if(x<0)x=(~x)+1;putchar('-');if(x>9)print(x/10);putchar(x%10+'0');
int gcd(int a,int b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;return t;
int n,T,a[10],typ[5],b[MAXN],dp[2][MAXM],tur[5][5],nxt[20][5],ans;
char str[MAXN];
int match(int x,int y)return (x^y)?x:2+x;
int ask(int x,int y)return x>1?x-2:(x^y);
signed main()
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	read(T);
	tur[0][0]=0;tur[0][1]=1;tur[0][2]=2;tur[0][3]=3;
	tur[1][0]=1;tur[1][1]=0;tur[1][2]=3;tur[1][3]=2;
	tur[2][0]=tur[2][1]=tur[2][2]=tur[2][3]=2;
	tur[3][0]=tur[3][1]=tur[3][2]=tur[3][3]=3;
	while(T--)
		for(int i=0;i<8;i++)scanf("%1d",&a[i]);
		for(int i=0;i<4;i++)typ[i]=match(a[i],a[i+4]);
		scanf("\\n%s",str+1);n=(int)strlen(str+1);
		for(int i=1;i<=n;i++)b[i]=(str[i]=='?'?2:((str[i]-'0')^1)),str[i]=0;
		for(int i=0;i<2;i++)for(int j=0;j<16;j++)dp[i][j]=0;
		int now=0,las=1;dp[now][1]=1;
		for(int i=0;i<16;i++)
			for(int k1=0;k1<2;k1++)
				for(int k2=0;k2<2;k2++)
					int S=k1|(k2<<1);nxt[i][S]=0;
					for(int j=0;j<4;j++)if((i>>j)&1)nxt[i][S]|=(1<<tur[j][typ[S]]);
					for(int j=0;j<4;j++)if((i>>j)&1)nxt[i][S]|=(1<<typ[ask(j,k1)|(k2<<1)]);
				
		for(int i=1;i<n;i+=2)
			swap(now,las);
			for(int j=0;j<16;j++)dp[now][j]=0;
			for(int k1=0;k1<2;k1++)if(b[i]^k1)
				for(int k2=0;k2<2;k2++)if(b[i+1]^k2)
					for(int j=0;j<16;j++)if(dp[las][j])
						Add(dp[now][nxt[j][k1|(k2<<1)]],dp[las][j],mo);
		
		for(int i=0;i<2;i++)if(b[n]^i)
			for(int j=0;j<16;j++)if(dp[now][j])
				bool flag=0;
				for(int k=0;k<4;k++)if((j>>k)&1)
					flag|=ask(k,i);
				if(flag)Add(ans,dp[now][j],mo);
			
		printf("%d\\n",ans);ans=0;
	
	return 0;

谢谢!!!

以上是关于[硫化铂]开心消消乐的主要内容,如果未能解决你的问题,请参考以下文章

Pygame实战开心——消消乐,你乐,我乐,大家乐~

开心消消乐 - 基于R

Unity3D_(游戏)开心消消乐

C语言风格实现的开心消消乐

自己写一个,开心消消乐!

仿开心消消乐 大树星星无限循环 点击(自定义view实现)