有一个长度为 n n n的数列 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,…,an,其中 1 ≤ a i ≤ 9 1\leq a_i\leq 9 1≤ai≤9。对于相邻两项的 a i a_i ai和 a i + 1 a_{i+1} ai+1,满足 gcd ( a i , a i + 1 ) = 1 \gcd(a_i,a_{i+1})=1 gcd(ai,ai+1)=1时,你可以通过一次操作交换 a i a_i ai和 a i + 1 ( 1 ≤ i < n ) a_{i+1}(1\leq i
求可以通过这样的操作获得多少个序列(包括原序列)。输出答案模 998244353 998244353 998244353后的值。
2 ≤ n ≤ 1 0 5 , 1 ≤ a i ≤ 9 2\leq n\leq 10^5,1\leq a_i\leq 9 2≤n≤105,1≤ai≤9
对于 a i = 1 / 5 / 7 a_i=1/5/7 ai=1/5/7时,这些数可以放在任意位置(注意交换两个相同的数相当于不交换),我们可以将其放在最后处理。下面只考虑不是 1 , 5 , 7 1,5,7 1,5,7的 a i a_i ai。
然后,我们将剩下的数分成 2 2 2的倍数和 3 3 3的倍数:
注意任意两个在 [ 1 , 9 ] [1,9] [1,9]中不相同的数的 gcd \gcd gcd如果不为 1 1 1,则一定能被 2 2 2或 3 3 3整除。
也就是说,在序列中,上面两类数的相对顺序是不变的。而 6 6 6和其他数都不能交换,也就是说 6 6 6的位置已经固定了。
对于两个 6 6 6之间的数,这些数中 2 2 2的倍数和 3 3 3的倍数这两类数没有交集。设有 x x x个数是 2 2 2的倍数,有 y y y个数是 3 3 3的倍数,那么就相当于要在这一段中选择 x x x个位置放 2 2 2的倍数,剩下的位置放 3 3 3的倍数,方案数为 ( x + y x ) \binom{x+y}{x} (xx+y)。把每一段的 ( x + y x ) \binom{x+y}{x} (xx+y)相乘即可。
下面考虑值为 1 / 5 / 7 1/5/7 1/5/7的 a i a_i ai的贡献。设 1 1 1的个数为 w 1 w_1 w1, 5 5 5的个数为 w 2 w_2 w2, 7 7 7的个数为 w 3 w_3 w3,上面得到的答案为 n o w now now,则答案为:
a n s = ( n w 1 + w 2 + w 3 ) ( w 1 + w 2 + w 3 w 1 ) ( w 2 + w 3 w 2 ) × n o w ans=\binom{n}{w_1+w_2+w_3}\binom{w_1+w_2+w_3}{w_1}\binom{w_2+w_3}{w_2}\times now ans=(w1+w2+w3n)(w1w1+w2+w3)(w2w2+w3)×now
也就是先在 n n n个位置中选出 w + w 2 + w 3 w_+w_2+w_3 w+w2+w3个位置放 1 , 5 , 7 1,5,7 1,5,7,并在这些位置中分配 1 , 5 , 7 1,5,7 1,5,7各自的位置,再乘上其他数的分配方案。
时间复杂度为 O ( n ) O(n) O(n)。
#include
using namespace std;
const int N=100000;
const long long mod=998244353;
int n,t1=0,w1=0,w2=0,w3=0,a[N+5],t[N+5];
long long ans=1,jc[N+5],ny[N+5];
long long mi(long long t,long long v){
if(!v) return 1;
long long re=mi(t,v/2);
re=re*re%mod;
if(v&1) re=re*t%mod;
return re;
}
void init(){
jc[0]=1;
for(int i=1;i<=N;i++) jc[i]=jc[i-1]*i%mod;
ny[N]=mi(jc[N],mod-2);
for(int i=N-1;i>=0;i--) ny[i]=ny[i+1]*(i+1)%mod;
}
long long C(int x,int y){
return jc[x]*ny[y]%mod*ny[x-y]%mod;
}
long long solve(int l,int r){
int v2=0,v3=0;
for(int i=l;i<=r;i++){
if(a[i]%2==0) ++v2;
else if(a[i]%3==0) ++v3;
}
return C(v2+v3,v2);
}
int main()
{
// freopen("b.in","r",stdin);
// freopen("b.out","w",stdout);
init();
scanf("%d",&n);
t[++t1]=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]==1) ++w1;
else if(a[i]==5) ++w2;
else if(a[i]==7) ++w3;
else if(a[i]==6) t[++t1]=i;
}
t[++t1]=n+1;
for(int i=1;i<t1;i++){
ans=ans*solve(t[i]+1,t[i+1]-1)%mod;
}
ans=ans*C(n,w1+w2+w3)%mod;
ans=ans*C(w1+w2+w3,w1)%mod*C(w2+w3,w2)%mod;
printf("%lld",ans);
return 0;
}