题目链接
https://codeforces.ml/gym/101002
题意
有个只有AB两种字符的串,求出每个k-inversion的个数。k-inversion是长度为k,收尾分别是B,A的子串。
题解
FFT板题。设
{
a
i
=
1
&
b
i
=
0
,
s
i
=
′
A
′
b
i
=
1
&
a
i
=
0
,
s
i
=
′
B
′
\left\{ \begin{array}{lr} a_i=1\&b_i=0,s_i='A'\\ b_i=1\&a_i=0,s_i='B' \end{array} \right.
{ai=1&bi=0,si=′A′bi=1&ai=0,si=′B′
那么
a
n
s
k
=
∑
i
=
0
,
j
=
0
,
i
+
(
−
j
)
=
=
k
i
<
n
,
j
<
n
a
i
∗
b
j
ans_k=\sum_{i=0,j=0,i+(-j)==k}^{i<n,j<n}a_i*b_j
ansk=i=0,j=0,i+(−j)==k∑i<n,j<nai∗bj
明显是卷积的形式。所以直接吧b数组倒过来。这样i-j变成了i+n-j-1。所以k的答案是结果数组的c[n-1+k]。
AC代码可以当板子:
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
const double pi=acos(-1.0);
using namespace std;
const int NN=2*1024*1014+100;
struct complex
{
double re,im;
complex(double r=0.0,double i=0.0) {re=r,im=i;}
void print() {printf("%lld\n",(long long)(re+0.5));}
} a[NN*2],b[NN*2],W[2][NN*2];
int N,na,nb,rev[NN*2];
complex operator +(const complex&A,const complex&B) {return complex(A.re+B.re,A.im+B.im);}
complex operator -(const complex&A,const complex&B) {return complex(A.re-B.re,A.im-B.im);}
complex operator *(const complex&A,const complex&B) {return complex(A.re*B.re-A.im*B.im,A.re*B.im+A.im*B.re);}
void FFT(complex*a,int f)
{
complex x,y;
for (int i=0; i<N; i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int i=1; i<N; i<<=1)
for (int j=0,t=N/(i<<1); j<N; j+=i<<1)
for (int k=0,l=0; k<i; k++,l+=t) x=W[f][l]*a[j+k+i],y=a[j+k],a[j+k]=y+x,a[j+k+i]=y-x;
if (f) for (int i=0; i<N; i++) a[i].re/=N;
}
void work()
{
for (int i=0; i<N; i++)
{
int x=i,y=0;
for (int k=1; k<N; x>>=1,k<<=1) (y<<=1)|=x&1;
rev[i]=y;
}
for (int i=0; i<N; i++) W[0][i]=W[1][i]=complex(cos(2*pi*i/N),sin(2*pi*i/N)),W[1][i].im=-W[0][i].im;
}
// void init()
// {
// scanf("%d",&na); for (int i=0; i<na; i++) scanf("%d",&a[i].re);
// scanf("%d",&nb); for (int i=0; i<nb; i++) scanf("%d",&b[i].re);
// for (N=1; N<na||N<nb; N<<=1); N<<=1;
// }
void solve()
{
work(),FFT(a,0),FFT(b,0);
for (int i=0; i<N; i++) a[i]=a[i]*b[i];
FFT(a,1);
}
char s[NN];
int main(){
scanf("%s",s);int n=strlen(s);
if(n==1){
printf("0\n");
return 0;
}
for(int i=0;i<n;i++){
if(s[i]=='A'){
a[i]=1;b[n-i-1]=0;
}
else{
a[i]=0;
b[n-i-1]=1;
}
}
na=n,nb=n;
for (N=1; N<na||N<nb; N<<=1); N<<=1;
solve();
for(int i=1;i<n;i++){
a[i+n-1].print();
}
return 0;
}