D e s c r i p t i o n Description Description
给 定 n 个 数 , 求 将 这 n 个 数 按 拼 在 一 起 形 成 一 个 大 数 , 这 个 大 数 是 是 11 的 倍 数 的 方 案 数 。 给定n个数,求将这n个数按拼在一起形成一个大数,这个大数是\\是11的倍数的方案数。 给定n个数,求将这n个数按拼在一起形成一个大数,这个大数是是11的倍数的方案数。
S o l u t i o n Solution Solution
对
于
这
题
,
我
们
首
先
得
想
到
一
个
数
学
性
质
对于这题,我们首先得想到一个数学性质
对于这题,我们首先得想到一个数学性质
10
≡
−
1
(
m
o
d
11
)
10 \equiv -1 (mod 11)
10≡−1(mod11)
对
于
这
个
性
质
,
比
如
a
,
b
,
c
三
个
数
拼
接
成
a
b
c
形
式
,
a
b
c
=
a
∗
1
0
l
e
n
(
b
+
c
)
+
b
∗
1
0
l
e
n
(
c
)
+
c
若
满
足
a
∗
1
0
l
e
n
(
b
+
c
)
+
b
∗
1
0
l
e
n
(
c
)
+
c
≡
0
(
m
o
d
11
)
则
可
化
为
a
∗
(
−
1
)
l
e
n
(
b
+
c
)
+
b
∗
(
−
1
)
l
e
n
(
c
)
+
c
≡
0
(
m
o
d
11
)
即
是
a
,
b
,
c
本
身
∗
各
自
所
在
的
奇
偶
位
是
11
的
倍
数
时
,
成
立
(
举
例
,
a
=
9
,
b
=
2
,
c
=
4
,
组
成
的
数
9
∗
1
+
2
∗
−
1
+
4
≡
0
,
故
924
是
11
的
倍
数
)
对于这个性质,比如 a,b,c三个数拼接成abc形式,\\ abc=a*10^{len(b+c)}+b*10^{len(c)}+c\\ 若满足a*10^{len(b+c)}+b*10^{len(c)}+c \equiv 0 (mod 11)\\ 则可化为a*(-1)^{len(b+c)}+b*(-1)^{len(c)}+c \equiv 0 (mod 11)\\ 即是a,b,c本身*各自所在的奇偶位是11的倍数时,成立\\ (举例,a=9,b=2,c=4,组成的数9*1+2*-1+4 \equiv 0 ,故924是11的倍数)
对于这个性质,比如a,b,c三个数拼接成abc形式,abc=a∗10len(b+c)+b∗10len(c)+c若满足a∗10len(b+c)+b∗10len(c)+c≡0(mod11)则可化为a∗(−1)len(b+c)+b∗(−1)len(c)+c≡0(mod11)即是a,b,c本身∗各自所在的奇偶位是11的倍数时,成立(举例,a=9,b=2,c=4,组成的数9∗1+2∗−1+4≡0,故924是11的倍数)
我
们
就
若
设
a
∗
1
,
a
在
奇
数
位
,
a
∗
−
1
,
a
在
偶
数
位
,
那
么
我
们
现
在
只
需
要
去
找
哪
些
数
在
偶
数
位
,
哪
些
数
在
奇
数
位
的
情
况
,
在
数
列
中
,
我
们
插
入
一
个
l
e
n
为
偶
数
的
数
字
,
不
会
改
变
后
续
的
奇
偶
位
情
况
情
况
,
而
插
入
一
个
l
e
n
为
奇
数
的
则
会
全
部
反
过
来
我们就若设a*1,a在奇数位,a*-1,a在偶数位,那么我们现在只需要去找\\ 哪些数在偶数位,哪些数在奇数位的情况,在数列中,我们插入一个len为\\ 偶数的数字,不会改变后续的奇偶位情况情况,而插入一个len为奇数的则会全部\\ 反过来
我们就若设a∗1,a在奇数位,a∗−1,a在偶数位,那么我们现在只需要去找哪些数在偶数位,哪些数在奇数位的情况,在数列中,我们插入一个len为偶数的数字,不会改变后续的奇偶位情况情况,而插入一个len为奇数的则会全部反过来
我
们
把
所
有
l
e
n
为
奇
数
的
数
统
计
出
来
,
设
置
这
些
数
在
奇
数
位
或
偶
数
位
的
时
候
,
和
为
k
时
有
多
少
方
案
,
那
么
剩
下
的
l
e
n
为
偶
数
的
数
,
直
接
插
入
就
好
了
,
不
会
影
响
数
字
本
身
所
在
的
奇
偶
位
,
设
l
e
n
为
奇
数
的
数
有
n
1
个
,
命
名
为
a
i
,
l
e
n
为
偶
数
有
n
2
个
,
命
名
为
b
i
我们把所有len为奇数的数统计出来,设置这些数在奇数位或偶数位的时候,和为k时\\ 有多少方案,那么剩下的len为偶数的数,直接插入就好了,不会影响数字本身所在的\\ 奇偶位,设len为奇数的数有n1个,命名为a_i,len为偶数有n2个,命名为b_i
我们把所有len为奇数的数统计出来,设置这些数在奇数位或偶数位的时候,和为k时有多少方案,那么剩下的len为偶数的数,直接插入就好了,不会影响数字本身所在的奇偶位,设len为奇数的数有n1个,命名为ai,len为偶数有n2个,命名为bi
设
f
[
i
]
[
j
]
[
k
]
为
l
e
n
为
奇
数
中
前
i
个
数
,
有
j
个
数
在
偶
数
位
时
,
和
为
k
的
方
案
有
多
少
设f[i][j][k]为len为奇数中前i个数,有j个数在偶数位时,和为k的方案有多少
设f[i][j][k]为len为奇数中前i个数,有j个数在偶数位时,和为k的方案有多少
设
g
[
i
]
[
j
]
[
k
]
为
l
e
n
为
偶
数
中
前
i
个
数
,
有
j
个
数
在
偶
数
位
时
,
和
为
k
的
方
案
有
多
少
设g[i][j][k]为len为偶数中前i个数,有j个数在偶数位时,和为k的方案有多少
设g[i][j][k]为len为偶数中前i个数,有j个数在偶数位时,和为k的方案有多少
l
e
n
为
奇
数
的
最
终
状
态
一
定
时
f
[
n
1
]
[
n
1
/
2
]
[
0..10
]
,
l
e
n
为
偶
数
可
以
任
意
len为奇数的最终状态一定时f[n1][n1/2][0..10],len为偶数可以任意
len为奇数的最终状态一定时f[n1][n1/2][0..10],len为偶数可以任意
状态转移方程为
f
[
i
]
[
j
]
[
k
]
=
f
[
i
−
1
]
[
j
]
[
k
−
a
[
i
]
]
+
f
[
i
−
1
]
[
j
−
1
]
[
k
+
a
[
i
]
]
f[i][j][k]=f[i−1][j][k−a[i]] + f[i−1][j−1][k+a[i]]
f[i][j][k]=f[i−1][j][k−a[i]]+f[i−1][j−1][k+a[i]]
g
[
i
]
[
j
]
[
k
]
=
g
[
i
−
1
]
[
j
]
[
k
−
b
[
i
]
]
+
g
[
i
−
1
]
[
j
−
1
]
[
k
+
b
[
i
]
]
g[i][j][k]=g[i-1][j][k-b[i]] + g[i-1][j-1][k+b[i]]
g[i][j][k]=g[i−1][j][k−b[i]]+g[i−1][j−1][k+b[i]]
而
f
[
n
1
]
[
n
1
/
2
]
[
0..10
]
对
于
每
一
个
只
是
表
示
n
1
/
2
个
偶
数
下
,
但
对
于
每
个
具
体
位
置
,
n
1
/
2
个
位
于
偶
数
位
的
数
和
n
1
−
n
1
/
2
个
位
于
奇
数
位
的
数
是
可
以
互
相
换
位
的
,
故
还
需
乘
以
(
n
1
/
2
)
!
∗
(
n
1
−
n
1
/
2
)
!
再
思
考
,
对
于
l
e
n
为
偶
数
中
的
情
况
,
g
[
n
2
]
[
j
]
[
k
]
中
,
有
j
个
数
在
偶
数
位
,
那
么
这
偶
数
位
得
位
于
n
1
−
n
1
/
2
个
数
之
后
,
变
成
了
一
个
组
合
数
问
题
,
j
个
球
放
在
n
1
−
n
1
/
2
个
盒
子
里
,
一
个
盒
子
可
放
任
意
多
个
球
,
盒
子
可
以
为
空
,
即
是
多
重
集
组
合
数
,
j
个
球
可
任
意
交
换
,
则
再
乘
j
!
,
对
于
n
2
−
j
个
放
在
奇
数
为
得
数
同
理
,
只
是
奇
数
位
多
了
一
个
第
一
位
可
以
放
,
则
是
n
2
−
j
个
球
放
在
n
1
/
2
+
1
个
盒
子
O
K
,
完
全
s
o
l
v
e
d
!
!
而f[n1][n1/2][0..10]对于每一个只是表示n1/2个偶数下,但对于每个具体位置, n1/2个位于偶数位的数和n1-n1/2个位于奇数位的数是可以互相换位的,故还需乘以\\ (n1/2)!*(n1-n1/2)!\\ 再思考,对于len为偶数中的情况,g[n2][j][k]中,有j个数在偶数位,那么这偶数位\\ 得位于n1-n1/2个数之后,变成了一个组合数问题,j个球放在n1-n1/2个盒子里,一个\\ 盒子可放任意多个球,盒子可以为空,即是多重集组合数,j个球可任意交换,\\ 则再乘j!,对于n2-j个放在奇数为得数同理,只是奇数位多了一个第一位可以放,\\ 则是n2-j个球放在n1/2+1个盒子\\ OK,完全solved!!
而f[n1][n1/2][0..10]对于每一个只是表示n1/2个偶数下,但对于每个具体位置,n1/2个位于偶数位的数和n1−n1/2个位于奇数位的数是可以互相换位的,故还需乘以(n1/2)!∗(n1−n1/2)!再思考,对于len为偶数中的情况,g[n2][j][k]中,有j个数在偶数位,那么这偶数位得位于n1−n1/2个数之后,变成了一个组合数问题,j个球放在n1−n1/2个盒子里,一个盒子可放任意多个球,盒子可以为空,即是多重集组合数,j个球可任意交换,则再乘j!,对于n2−j个放在奇数为得数同理,只是奇数位多了一个第一位可以放,则是n2−j个球放在n1/2+1个盒子OK,完全solved!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//#pragma GCC optimize(3, "Ofast", "inline")
#define fir(i, a, b) for (int i = a; i <= b; i++)
#define mov(i) (1ll << i)
#define MAX_INF 0x3f3f3f3f
ll qpow(ll a, ll b, ll p)
{
ll ans = 1;
while (b)
{
if (b & 1)
ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans;
}
const int maxn = 2e3 + 10;
int a[maxn],b[maxn];
int mod = 998244353;
int f[2][maxn][12],g[2][maxn][12];//直接开数组MLE,状态压缩以下
inline int add(ll a,ll b)
{
return (a+b+mod)%mod;
}
ll fac[maxn], invfac[maxn], t[maxn];
void init(int n, ll MOD)
{
fac[0] = 1;
mod = MOD;
for (int i = 1; i <= n; i++)
fac[i] = fac[i - 1] * i % mod;
invfac[n] = qpow(fac[n], mod - 2, mod);
for (int i = n; i >= 1; i--)
invfac[i - 1] = invfac[i] * i % mod;
}
ll C(ll n, ll m)//求组合数
{
return n >= m ? fac[n] * invfac[n - m] % mod * invfac[m] % mod : 0;
}
//多重集排列数
ll cal(ll n,ll m)
{
if(!m) return (n==0);//n,m可能均为0
return fac[n]*C(n+m-1,m-1)%mod;
}
int main()
{
// input();
int T;
init(maxn-1,mod);
fac[0]=1;
cin >> T;
while(T--)
{
int n;
cin>>n;
int cnta=0,cntb=0;
fir(i,1,n)
{
int x;
scanf("%d",&x);
if(to_string(x).size()&1)
a[++cnta]=x%11;
else
b[++cntb]=x%11;
}
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
f[0][0][0]=1;g[0][0][0]=1;
for(int i=1;i<=cnta;i++)
{
int curi=i&1,lasti=!(i&1);
for(int j=0;j<=i;j++)
{
fir(k,0,10)
{
f[curi][j][k]=add(f[curi][j][k],f[lasti][j][(k-a[i]+11)%11]);
if(j)
f[curi][j][k]=add(f[curi][j][k],f[lasti][j-1][(k+a[i])%11]);
}
}
memset(f[lasti],0,sizeof(f[lasti]));
}
for(int i=1;i<=cntb;i++)
{
int curi=i&1,lasti=!(i&1);
for(int j=0;j<=i;j++)
{
fir(k,0,10)
{
g[curi][j][k]=add(g[curi][j][k],g[lasti][j][(k-b[i]+11)%11]);
if(j)
g[curi][j][k]=add(g[curi][j][k],g[lasti][j-1][(k+b[i])%11]);
}
}
memset(g[lasti],0,sizeof(g[lasti]));
}
ll ans=0;
ll temp=fac[cnta/2]*fac[cnta-cnta/2]%mod;
int m=cnta/2+1;
// cout<<"temp:"<<temp<<endl;
for(int i=0;i<=cntb;i++)
{
for(int j=0;j<11;j++)
{
int p=cntb-i;
ll val=(ll)g[cntb&1][i][j]*f[cnta&1][cnta/2][(11-j)%11]%mod*temp%mod*cal(p,m)%mod*cal(i,cnta-cnta/2)%mod;
ans=(ans+val)%mod;
}
}
printf("%lld\n",ans);
}
}