如何求
T
T
T 次操作之后,对于所有的
0
≤
i
≤
k
0\le i\le k
0≤i≤k ,求出最后恰好有
i
i
i 个家具不在原来的房间内的方案数
容易设计一个 DP
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示
i
i
i 次操作之后,恰好有
j
j
j 个家具不在原来的房间内的方案数
转移(自行理解)
f
[
0
]
[
0
]
=
1
f[0][0]=1
f[0][0]=1
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
×
j
×
(
n
−
2
)
+
f
[
i
−
1
]
[
j
−
1
]
×
(
k
−
j
+
1
)
×
(
n
−
1
)
+
f
[
i
−
1
]
[
j
+
1
]
×
(
j
+
1
)
f[i][j]=f[i-1][j]\times j\times(n-2)+f[i-1][j-1]\times(k-j+1)\times(n-1)+f[i-1][j+1]\times(j+1)
f[i][j]=f[i−1][j]×j×(n−2)+f[i−1][j−1]×(k−j+1)×(n−1)+f[i−1][j+1]×(j+1)
可以预处理转移矩阵
A
A
A 和初始向量
S
t
St
St
取参数
S
S
S 使得
S
2
+
S
−
1
≤
max
T
S^2+S-1\le\max T
S2+S−1≤maxT (
max
T
=
998244352
\max T=998244352
maxT=998244352 )
然后对于所有的
0
≤
i
≤
S
0\le i\le S
0≤i≤S 预处理出矩阵
A
i
A^i
Ai 和
(
A
S
)
i
(A^S)^i
(AS)i
那么
A
n
×
S
t
=
(
A
S
)
⌊
n
S
⌋
×
(
A
n
 
m
o
d
 
S
×
S
t
)
A^n\times St=(A^S)^{\lfloor\frac nS\rfloor}\times(A^{n\bmod S}\times St)
An×St=(AS)⌊Sn⌋×(AnmodS×St)
可以
O
(
S
k
3
)
O(Sk^3)
O(Sk3) 预处理
O
(
k
2
)
O(k^2)
O(k2) 单次询问,其中
S
=
O
(
P
)
S=O(\sqrt P)
S=O(P)
Task 2
对于每个
S
S
S 和
i
i
i ,预处理出与方案
S
S
S 恰好有
i
i
i 个家具的摆放位置不同的所有方案的得分之和
考虑和子集和变换一样,设
F
[
S
]
[
i
]
[
j
]
F[S][i][j]
F[S][i][j] 表示方案的前
i
i
i 个家具中恰好有
j
j
j 个家具摆放位置与
S
S
S 不同,后
k
−
i
k-i
k−i 个家具的摆放位置与
S
S
S 都一样的方案数
F
[
S
]
[
0
]
[
0
]
=
a
S
F[S][0][0]=a_S
F[S][0][0]=aS
(
a
S
a_S
aS 为方案
S
S
S 的得分)
F
[
S
]
[
i
]
[
j
]
=
F
[
S
]
[
i
−
1
]
[
j
]
+
∑
r
e
p
l
a
c
e
(
S
,
i
,
h
)
≠
S
F
[
r
e
p
l
a
c
e
(
S
,
i
,
h
)
]
[
i
−
1
]
[
j
−
1
]
F[S][i][j]=F[S][i-1][j]+\sum_{replace(S,i,h)\ne S}F[replace(S,i,h)][i-1][j-1]
F[S][i][j]=F[S][i−1][j]+replace(S,i,h)̸=S∑F[replace(S,i,h)][i−1][j−1]
r
e
p
l
a
c
e
(
S
,
i
,
h
)
replace(S,i,h)
replace(S,i,h) 表示把方案
S
S
S 中第
i
i
i 件家具移到房间
h
h
h 得到的方案
∑
\sum
∑ 内的东西可以利用前缀和等方法求
O
(
k
2
n
k
)
O(k^2n^k)
O(k2nk)
Solution
回到问题
根据常识,
T
T
T 次操作之后,对于每个
i
i
i ,都满足:对于所有的方案
S
S
S 满足
a
a
a 和
S
S
S 中恰好
i
i
i 个家具的所处房间不同,从初始状态
a
a
a 到达末状态
S
S
S 的方案数都一样
于是对于一个特定的状态
S
S
S ,如果
a
a
a 和
S
S
S 中恰好
i
i
i 个家具摆放位置不同
那么从状态
a
a
a 到达状态
S
S
S 的方案数可以用 Task 1 中的矩阵乘法算出,为
f
[
T
]
[
i
]
C
k
i
(
n
−
1
)
i
\frac{f[T][i]}{C_k^i(n-1)^i}
Cki(n−1)if[T][i]
其中
C
C
C 为组合数
于是一次询问
(
a
,
T
)
(a,T)
(a,T) 答案为
∑
i
=
0
k
f
[
T
]
[
i
]
C
k
i
(
n
−
1
)
i
×
F
[
S
]
[
k
]
[
i
]
\sum_{i=0}^k\frac{f[T][i]}{C_k^i(n-1)^i}\times F[S][k][i]
i=0∑kCki(n−1)if[T][i]×F[S][k][i]
总复杂度
O
(
P
k
3
+
k
2
n
k
+
q
k
2
)
O(\sqrt Pk^3+k^2n^k+qk^2)
O(Pk3+k2nk+qk2)
Code
常数巨大,见谅
#include<bits/stdc++.h>template<classT>inlinevoidread(T &res){
res =0;bool bo =0;char c;while(((c =getchar())<'0'|| c >'9')&& c !='-');if(c =='-') bo =1;else res = c -48;while((c =getchar())>='0'&& c <='9')
res =(res <<3)+(res <<1)+(c -48);if(bo) res =~res +1;}constint N =1e6+5, L =4e4+5, M =22, ZZQ =998244353;int n, k, q, a[N], lstans =1, f[N][M], pw1[M], pw[M], C[M][M], p1[M], p2[M],
dw1[M], sum[N][M];inlinevoidadd(int&a,constint&b){
a += b;if(a >= ZZQ) a -= ZZQ;}intqpow(int a,int b){int res =1;while(b){if(b &1) res =1ll* res * a % ZZQ;
a =1ll* a * a % ZZQ;
b >>=1;}return res;}struct matrix
{int n, m, a[M][M];matrix(){}matrix(int _n,int _m):n(_n),m(_m){memset(a,0,sizeof(a));}friendinline matrix operator*(const matrix &a,const matrix &b){
matrix res =matrix(a.n, b.m);for(int i =1; i <= res.n; i++)for(int j =1; j <= res.m; j++)for(int k =1; k <= a.m; k++)add(res.a[i][j],1ll* a.a[i][k]* b.a[k][j]% ZZQ);return res;}} s0[L], s1[L], St, Tr;intmain(){int S, T;read(n);read(k);read(q);for(int i =0; i <= k; i++) C[i][0]=1;for(int i =1; i <= k; i++)for(int j =1; j <= i; j++)
C[i][j]=(C[i -1][j]+ C[i -1][j -1])% ZZQ;
pw[0]= pw1[0]= dw1[0]=1;for(int i =1; i <= k; i++){
pw[i]= pw[i -1]* n; pw1[i]= pw1[i -1]*(n -1);
dw1[i]=qpow(pw1[i], ZZQ -2);
C[k][i]=qpow(C[k][i], ZZQ -2);}for(int i =0; i < pw[k]; i++)read(a[i]);for(int i =0; i < pw[k]; i++) f[i][0]= a[i];for(int i =1; i <= k; i++){if(n ==2)for(int j = i; j >=1; j--)for(int S =0; S < pw[k]; S++)add(f[S][j], f[S ^(1<< i -1)][j -1]);elsefor(int j =0; j <= i; j++)for(int S =0; S < pw[k]; S++){int id = S / pw[i -1]% n;
sum[S][j]= f[S][j];if(id)add(sum[S][j], sum[S - pw[i -1]][j]);add(f[S][j], sum[S +(n -1- id)* pw[i -1]][j -1]);add(f[S][j], ZZQ - sum[S][j -1]);if(id)add(f[S][j], sum[S - pw[i -1]][j -1]);}}
s0[0]= Tr =matrix(k +1, k +1);for(int i =1; i <= k +1; i++) s0[0].a[i][i]=1;
s1[0]= s0[0];for(int i =0; i <= k; i++){if(i) Tr.a[i +1][i]=(k - i +1)*(n -1);
Tr.a[i +1][i +1]= i *(n -2);if(i < k) Tr.a[i +1][i +2]= i +1;}
St =matrix(k +1,1); St.a[1][1]=1;for(int i =1; i <=33333; i++)
s0[i]= s0[i -1]* Tr;for(int i =1; i <=33333; i++)
s1[i]= s1[i -1]* s0[33333];while(q--){read(S);read(T);
T =1ll* T * lstans % ZZQ;
matrix A = s1[T /33333]*(s0[T %33333]* St);
lstans =0;for(int i =0; i <= k; i++)add(lstans,1ll* A.a[i +1][1]* dw1[i]% ZZQ * C[k][i]% ZZQ
* f[S][i]% ZZQ);printf("%d\n", lstans);}return0;}