【题解】arc189_a Reversi 2
arc189_a Reversi 2
简要题意
给定一个序列 \(b\),初始时 \(b_i=i\bmod 2\)。
输入一个序列 \(a\),\(a_i\in \{0,1\}\)。
可以进行任意次如下操作:
- 选定 \(l,r(r-l>1)\),对每一个 \(i\in [l+1,r-1]\),执行 \(a_i\leftarrow a_l\)。
当然,执行是有条件的,得满足 \(a_l=a_r\),且 \(\forall i\in [l+1,r-1],a_i\neq a_l\)。
问有多少种不同的操作序列能使得 \(b\) 变换为 \(a\)。
题解
知识点:排列组合。
启发:
- 多重集排列数
典型的 ARC style 题目,小巧精妙,适合静下心仔细推敲。
看着没什么思路,不妨找点性质。
选定的 \(l,r\),要求 \(a_l=a_r\),操作前还需要满足 \(\forall i\in [l+1,r-1],a_i\neq a_l\),操作是将 \(a_{l+1}\sim a_{r-1}\) 赋值为 \(a_l\),所以这个操作可以看作给 \(a_{l+1}\sim a_{r-1}\) 取反。
当一个 \(i\) 被之前的操作成功取反后,\(i\) 在之后将无法作为一个 \(l\) 或者 \(r\) 参与操作,因为肯定有 \(a_{i-1}=a_i=a_{i+1}\)。
当一个 \(i\) 作为 \(l\) 后,将不可能再作为 \(l\)。
同理,当一个 \(i\) 作为 \(r\) 后,也不可能再作为 \(r\)。
考虑对 \(a\) 每一个颜色段(连续的 0 或者 1)求解,相邻颜色段间是独立的,原因是操作的 \(l,r\) 应该满足 \(a_l=a_r\)。
每一个段的长度一定是奇数,不然无解,因为此时 \(b\) 的左端点和右端点不同,无法操作成同色。
长度为 \(1\) 的段对答案无贡献,无法进行操作,不过不能忽略,因为要判无解。
考虑什么时候无解,对于段 \([l,r]\),以下情况会导致无解:
-
\(a_l\neq a_r\)
-
\(a_l\neq l\bmod 2\)
-
\(a_r\neq r\bmod 2\)
可以发现上面的条件已经顺便把 \(r-l+1\) 为奇数判了。
现在考虑每个颜色段的贡献计算,目的是将 01 交替的段转化为全为 0 或者 1 的段,由于两种情况通过置换后完全等价,只考虑将 1 开头并 01 交替的段转化为全为 1 的段。
设一个 01 交替段长度为 \(len\)。
初始时共有 \(len-2\) 对 \((l,r)\) 可进行操作,每次操作后,对数都会减少 \(2\),直到减少到 \(1\),此时再操作,便成为了全 1 的段,故不管怎么操作,操作次数都为 \(\lfloor \frac{len-2}{2} \rfloor +1=\frac{len-1}{2}\) 次。
准备进行第 \(i\) 次操作时,有 \(len-2-2(i-1)=len-2i\) 对可选的 \((l,r)\) 操作,故操作方案数为 \(\displaystyle \prod_{i=1}^\frac{len-1}{2} (len-2i)=\prod_{i=1}^{\frac{len-1}{2}} (2i-1)\)。
接下来考虑段之间贡献的合并。
除了简单地将各自的操作方案数相乘,还得考虑到操作可以交替进行,段之间的操作存在顺序,段内的顺序已经被前面考虑,所以要用到多重集的排列数,设有 \(k\) 个段,第 \(i\) 个段有 \(s_i\) 次操作,设 \(\displaystyle N=\sum_{i=1}^k{s_i}\),则排列数为:
设段长为 \(l_i\),那么总的答案就是:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 202507
#define int long long
const int mod=998244353;
int n,a[N],fac[N],cnt[N];
inline int inv(int a){
int b=mod-2,ans=1;
while(b){
if(b&1){
ans=ans*a%mod;
}
a=a*a%mod;
b>>=1;
}
return ans;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
fac[0]=1;
rep(i,1,n){
cin>>a[i];
fac[i]=fac[i-1]*i%mod;
}
{
cnt[3]=1;
int st=5;
while(st<=n){
cnt[st]=cnt[st-2]*(st-2)%mod;
st+=2;
}
}
vector<pr>v;
int sum=0;
int ls=1;
rep(i,1,n){
if(a[i]!=a[ls]){
int l=ls,r=i-1;
sum+=(r-l)/2;
v.pb({ls,i-1});
ls=i;
}
}
v.pb({ls,n});
sum+=(n-ls)/2;
int ans=fac[sum];
for(pr u:v){
int l=u.fi,r=u.se;
if(a[l]!=a[r]||a[l]!=l%2||a[r]!=r%2){
cout<<0;
return 0;
}
if(l==r){
continue;
}
ans=ans*inv(fac[(r-l)/2])%mod;
ans=ans*cnt[r-l+1]%mod;
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号