假设地球是完美球体。
对于球上的两个点 x , y x,y x,y ,定义 w x , y w_{x,y} wx,y 为从 x x x 向西到 y y y 的距离, e x , y e_{x,y} ex,y 为从 x x x 向东到 y y y 的距离。
若
w
y
,
x
<
e
y
,
x
w_{y,x}
若
w
y
,
x
<
e
y
,
x
w_{y,x}
定义大小为 n × n n\times n n×n 的方向矩阵 D D D 为:
称方向矩阵 D D D 为真实的,当赤道上存在 n n n 个不同的位置 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an 满足:
现在给定某些元素被’?‘表示的方向矩阵 D D D ,每个’?‘可以被替换为’W’或’E’,求有多少真实的方向矩阵可以通过替换’?'得到。
假设
a
2
,
a
3
,
.
.
.
,
a
p
a_2,a_3,...,a_p
a2,a3,...,ap 在
a
1
a_1
a1 的东面,
a
p
+
1
,
a
p
+
2
,
.
.
.
,
a
n
a_{p+1},a_{p+2},...,a_n
ap+1,ap+2,...,an 在
a
1
a_1
a1 的西面。
将
a
2
,
a
3
,
.
.
.
,
a
p
a_2,a_3,...,a_p
a2,a3,...,ap 通过球心投影到
a
1
a_1
a1 的东面得到对应点
a
2
′
,
a
3
′
,
.
.
.
,
a
p
′
a_2',a_3',...,a_p'
a2′,a3′,...,ap′ 。
现在
a
i
(
2
≤
i
≤
p
)
a_i(2\le i\le p)
ai(2≤i≤p) 与
a
j
(
p
+
1
≤
j
≤
n
)
a_j(p+1\le j\le n)
aj(p+1≤j≤n) 的关系可以对应到
a
j
a_j
aj 与
a
i
′
a_i'
ai′ 的关系。
以下称
x
x
x 在
y
y
y 的西面为
x
<
y
x
那么问题转化为求
a
2
′
,
a
3
′
,
.
.
.
,
a
p
′
(
a
2
′
<
a
3
′
<
.
.
.
<
a
p
′
)
a_2',a_3',...,a_p'(a_2'
下文中的
a
i
′
a_i'
ai′ 指第
i
i
i 个
a
′
a'
a′ (即原来的
a
i
+
1
′
a_{i+1}'
ai+1′ ),
a
i
a_i
ai 指第
i
i
i 个
a
a
a (即原来的
a
p
+
i
a_{p+i}
ap+i )
设
a
′
a'
a′ 共有
x
(
x
=
p
−
1
)
x(x=p-1)
x(x=p−1) 个,
a
a
a 共有
y
(
y
=
n
−
p
)
y(y=n-p)
y(y=n−p) 个。
设
f
i
,
j
f_{i,j}
fi,j 表示前
i
i
i 个
a
′
a'
a′ 和前
j
j
j 个
a
a
a 可构成的上升序列数。
每次枚举第个
a
i
′
a_i'
ai′ 的位置,可得转移式:
f
i
,
j
=
∑
k
=
0
j
f
i
−
1
,
k
×
g
i
,
k
f_{i,j}=\sum_{k=0}^jf_{i-1,k}\times g_{i,k}
fi,j=k=0∑jfi−1,k×gi,k
其中
g
i
,
k
g_{i,k}
gi,k 表示
a
i
′
a_i'
ai′ 能否位于
a
k
a_k
ak 与
a
k
+
1
a_{k+1}
ak+1 之间,可得:
g
i
,
j
=
∏
k
=
1
j
[
a
k
<
a
i
′
]
∏
k
=
j
+
1
y
[
a
i
′
<
a
k
]
g_{i,j}=\prod_{k=1}^j[a_k
通过预处理前缀和后缀可以
O
(
n
2
)
O(n^2)
O(n2) 得到所有的
g
g
g 。
但是原先的
d
p
dp
dp 的复杂度是
O
(
n
3
)
O(n^3)
O(n3) 的(状态
O
(
n
2
)
O(n^2)
O(n2) ,转移
O
(
n
)
O(n)
O(n) ),如果在此同时枚举
p
p
p 则总复杂度为
O
(
n
4
)
O(n^4)
O(n4) ,不能通过。
再次观察转移式
f
i
,
j
=
∑
k
=
0
j
f
i
−
1
,
k
×
g
i
,
k
f_{i,j}=\sum\limits_{k=0}^jf_{i-1,k}\times g_{i,k}
fi,j=k=0∑jfi−1,k×gi,k ,发现
f
i
,
j
f_{i,j}
fi,j 与
f
i
,
j
−
1
f_{i,j-1}
fi,j−1 的差别只有
f
i
−
1
,
j
×
g
i
,
j
f_{i-1,j}\times g_{i,j}
fi−1,j×gi,j 一项,因而前缀和优化后可得递推式:
f
i
,
j
=
f
i
,
j
−
1
+
f
i
−
1
,
j
×
g
i
,
j
f_{i,j}=f_{i,j-1}+f_{i-1,j}\times g_{i,j}
fi,j=fi,j−1+fi−1,j×gi,j
状态 O ( n 2 ) O(n^2) O(n2) ,转移 O ( 1 ) O(1) O(1) , d p dp dp 复杂度为 O ( n 2 ) O(n^2) O(n2) ,再算上枚举 p p p 的 O ( n ) O(n) O(n) ,程序总复杂度为 O ( n 3 ) O(n^3) O(n3) ,可以通过。
注意判断判断初始的矩阵是否合法,同时根据对称将矩阵问号可以直接填充。
#include
using namespace std;
template<class T>inline void read(T&x){
char c,last=' ';
while(!isdigit(c=getchar()))last=c;
x=c^48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+(c^48);
if(last=='-')x=-x;
}
const int MAXN=5e2+7,P=998244353;
int n;
int x,y;
string s[MAXN];
int a[MAXN];
int b[MAXN];
int f[MAXN][MAXN];
int g[MAXN][MAXN];
int check(){//判断是否合法,并填补已经确定的'?'
for(int i=1;i<=n;++i){
for(int j=1;j<i;++j){
if(s[i][j]==s[j][i]&&s[i][j]!='?')return 1;//W-W或E-E
if(s[i][j]!=s[j][i]){//对称填充
if(s[i][j]=='W')s[j][i]='E';
if(s[i][j]=='E')s[j][i]='W';
if(s[j][i]=='W')s[i][j]='E';
if(s[j][i]=='E')s[i][j]='W';
}
}
}
return 0;
}
void init(){//预处理g数组
static int pre[MAXN][MAXN];
static int suf[MAXN][MAXN];
for(int i=1;i<=x;++i){
pre[i][0]=suf[i][y+1]=1;
for(int j=1;j<=y;++j){//预处理前缀(0~y)
pre[i][j]=pre[i][j-1]&(s[a[i]][b[j]]!='E');
}
for(int j=y;j>=1;--j){//预处理后缀(1~y+1)
suf[i][j]=suf[i][j+1]&(s[a[i]][b[j]]!='W');
}
for(int j=0;j<=y;++j)g[i][j]=pre[i][j]&suf[i][j+1];//计算(0~y)
}
}
void work(){
init();
for(int j=0;j<=y;++j)f[0][j]=1;//dp预处理
for(int i=1;i<=x;++i){
for(int j=0,sum=0;j<=y;++j){
sum=(sum+g[i][j]*f[i-1][j])%P;//前缀和优化(直接使用递推式需要特判下标f[-1])
f[i][j]=sum;
}
}
}
int main()
{
int T;read(T);
while(T--){
read(n);
for(int i=1;i<=n;++i){
cin>>s[i];
s[i]=" "+s[i];
}
if(check()){//原矩阵非法
puts("0");
continue;
}
int ans=0;
for(int i=1;i<=n;++i){
int flag=x=y=0;
for(int j=2;j<=i;++j){
a[++x]=j;
flag|=s[j][1]=='W';
for(int k=2;k<j;++k){
flag|=s[j][k]=='W';
}
}
for(int j=i+1;j<=n;++j){
b[++y]=j;
flag|=s[j][1]=='E';
for(int k=n;k>j;--k){
flag|=s[j][k]=='E';
}
}
if(flag)continue;//划分方案有误
work();
ans=(ans+f[x][y])%P;
}
cout<<ans<<'\n';
}
return 0;
}