[AGC058D]Yet Another ABC String
Yet Another ABC String
题解
首先看到这个题,一个方向是去考虑容斥。
可以发现,如果有连续不合法部分的话,可以发现,他一定是一段连续的
.
.
.
A
B
C
A
B
C
A
B
C
A
B
C
.
.
.
...ABCABCABCABC...
...ABCABCABCABC...。
这是一个非常好的性质,因为如果我们之间容斥不合法位置的起点集合的话是非常麻烦的,这可以让我们得到一个非常好的转化。
每次强制原串中的一些部分呈现我们上面所说的这样的连续段,容斥我们这些连续段的集合。
考虑选择一个这样长度为
n
n
n的段,它所贡献容斥系数。
手推一下前几项可以发现,容斥系数在模
3
3
3为
0
0
0的位置上为
−
1
-1
−1,在模
3
3
3为
1
1
1的位置上为
1
1
1,模
3
3
3为
2
2
2的位置上为
0
0
0。
证明大概可以考虑通过递推式归纳证明,不是很会证明。(先留个坑)
好的,既然知道这东西了,我们也就很容易设计出来一个
d
p
dp
dp转移。
由于有效的要么是模
3
3
3为
0
0
0,要么模
3
3
3为
1
1
1,相当于要么让所有数都减去同样的个数,要么在这基础上挑一个数多减一次。
定义
d
p
i
,
j
dp_{i,j}
dpi,j表示在构造一个长度为
i
i
i的串,让每个数减去
i
−
j
3
\frac{i-j}{3}
3i−j,并且,进行
j
j
j次挑一个数多减
1
1
1的操作,得到的总系数和。
可以得到其转移式:
d
p
i
,
j
=
d
p
i
−
1
,
k
−
1
+
∑
k
=
1
min
(
i
,
3
j
+
1
)
[
k
≡
1
(
m
o
d
3
)
]
d
p
i
−
k
,
j
−
k
−
1
3
−
3
[
k
≡
0
(
m
o
d
3
)
]
d
p
i
−
k
,
j
−
k
3
dp_{i,j}=dp_{i-1,k-1}+\sum_{k=1}^{\min(i,3j+1)}[k\equiv 1\pmod{3}]dp_{i-k,j-\frac{k-1}{3}}-3[k\equiv 0\pmod{3}]dp_{i-k,j-\frac{k}{3}}
dpi,j=dpi−1,k−1+k=1∑min(i,3j+1)[k≡1(mod3)]dpi−k,j−3k−1−3[k≡0(mod3)]dpi−k,j−3k其中
d
p
i
−
1
,
k
−
1
dp_{i-1,k-1}
dpi−1,k−1表示这个位置没被选择容斥,
3
3
3的系数是由于模
3
3
3为
0
0
0的情况有
A
B
C
,
B
C
A
,
C
A
B
ABC,BCA,CAB
ABC,BCA,CAB三种结构,模
3
3
3为
1
1
1的情况结构是固定的,没必要乘
3
3
3。
答案显然可以通过
d
p
dp
dp值算出来,有
A
n
s
=
∑
(
n
−
3
i
A
−
i
,
B
−
i
,
C
−
i
)
d
p
n
,
n
−
i
Ans=\sum\binom{n-3i}{A-i,B-i,C-i}dp_{n,n-i}
Ans=∑(A−i,B−i,C−in−3i)dpn,n−i。
再对上面的式子根据模
3
3
3余数加个前缀和优化,我们就得到一个简单的
O
(
n
2
)
O\left(n^2\right)
O(n2)的
d
p
dp
dp做法了。
接下来让我们来看看怎么优化上面的这个
d
p
dp
dp,不妨考虑生成函数。
定义二元生成函数
G
(
x
,
y
)
G(x,y)
G(x,y),其中
[
x
i
y
j
]
G
[x^iy^j]G
[xiyj]G代表
d
p
i
,
j
dp_{i,j}
dpi,j的值。
通过
G
G
G的递推式可以得到,
F
=
x
+
∑
i
=
1
∞
x
3
i
+
1
y
i
−
3
x
3
i
y
i
=
x
−
3
x
3
y
1
−
x
3
y
G
=
∑
i
=
0
∞
F
i
=
1
1
−
F
(
x
,
y
)
=
1
−
x
3
y
1
−
x
+
2
x
3
y
F=x+\sum_{i=1}^{\infty}x^{3i+1}y^i-3x^{3i}y^i=\frac{x-3x^3y}{1-x^3y}\\ G=\sum_{i=0}^{\infty} F^i=\frac{1}{1-F(x,y)}=\frac{1-x^3y}{1-x+2x^3y}\\
F=x+i=1∑∞x3i+1yi−3x3iyi=1−x3yx−3x3yG=i=0∑∞Fi=1−F(x,y)1=1−x+2x3y1−x3y同样,考虑现在答案怎么计算。
A
n
s
=
∑
i
=
0
min
(
A
,
B
,
C
)
(
n
−
3
i
A
−
i
,
B
−
i
,
C
−
i
)
[
x
n
y
i
]
G
Ans=\sum_{i=0}^{\min(A,B,C)}\binom{n-3i}{A-i,B-i,C-i}[x^ny^i]G
Ans=i=0∑min(A,B,C)(A−i,B−i,C−in−3i)[xnyi]G令
G
′
=
1
1
−
x
+
2
x
3
y
=
∑
(
x
−
2
x
3
y
)
i
G'=\frac{1}{1-x+2x^3y}=\sum (x-2x^3y)^i
G′=1−x+2x3y1=∑(x−2x3y)i,显然有
[
x
n
y
m
]
G
=
[
x
n
y
m
]
G
′
−
[
x
n
−
3
y
m
−
1
]
G
′
[x^ny^m]G=[x^ny^m]G'-[x^{n-3}y^{m-1}]G'
[xnym]G=[xnym]G′−[xn−3ym−1]G′>
现在我们就只需要考虑
[
x
n
y
m
]
G
′
[x^ny^m]G'
[xnym]G′怎么算了,这个好搞,可以解方程,看两边分别贡献了多少。
有
a
−
3
b
=
n
,
b
=
m
⇒
a
=
n
−
3
m
a-3b=n,b=m\Rightarrow a=n-3m
a−3b=n,b=m⇒a=n−3m,所以根据二项式定理可得,
[
x
n
y
m
]
G
′
=
(
n
−
2
m
m
)
(
−
2
)
m
[x^ny^m]G'=\binom{n-2m}{m}(-2)^m
[xnym]G′=(mn−2m)(−2)m带到上面的式子里面去就可以快速算出答案了。
时间复杂度 O ( A + B + C ) O\left(A+B+C\right) O(A+B+C)。
源码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define MAXN 3000005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){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>
_T Fabs(_T x){return x<0?-x:x;}
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*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int nA,nB,nC,n,fac[MAXN],inv[MAXN],ff[MAXN],pw2[MAXN],ans;
void init(){
fac[0]=fac[1]=inv[0]=inv[1]=ff[1]=pw2[0]=1;
for(int i=2;i<=n;i++)
fac[i]=1ll*i*fac[i-1]%mo,
ff[i]=1ll*(mo-mo/i)*ff[mo%i]%mo,
inv[i]=1ll*ff[i]*inv[i-1]%mo;
for(int i=1;i<=n;i++)pw2[i]=mo-add(pw2[i-1],pw2[i-1],mo);
}
int C(int x,int y){
if(x<0||y<0||x<y)return 0;
return 1ll*fac[x]*inv[y]%mo*inv[x-y]%mo;
}
int work(int x,int y){
if(x<0||y<0||x<y+y)return 0;
return 1ll*pw2[y]*C(x-y-y,y)%mo;
}
signed main(){
read(nA);read(nB);read(nC);n=nA+nB+nC;init();
for(int i=0;i<=min(nA,min(nB,nC));i++){
int tmp=add(work(n,i),mo-work(n-3,i-1),mo);
Add(ans,1ll*C(n-i*3,nA-i)*C(n-i*2-nA,nB-i)%mo*tmp%mo,mo);
}
printf("%d\n",ans);
return 0;
}