[硫化铂]开心消消乐
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;
谢谢!!!
以上是关于[硫化铂]开心消消乐的主要内容,如果未能解决你的问题,请参考以下文章