D
e
s
c
r
i
p
t
i
o
n
\mathcal{Description}
Description
多组询问
1
≤
n
,
Q
≤
1
0
5
1 \leq n,Q\leq 10^5
1≤n,Q≤105
S o l u t i o n \mathcal{Solution} Solution
50 50 50分解法
考虑
D
P
DP
DP,感觉上直接算答案不好算,所以考虑算长度为
n
n
n的所有排列改变的次数的排列的个数算出来
之后再把个数乘以次数的平方即可
设
f
i
,
j
f_{i,j}
fi,j表示长度为
i
i
i的排列的改变次数为
j
j
j的排列个数
考虑把最大的
i
i
i插入到长度为
i
−
1
i-1
i−1的改变次数为
j
j
j的排列中,则有
i
i
i个空可以插,其中最前面的空插进去会使改变次数加一,所以有
i
−
1
i-1
i−1个空使改变次数不变
考虑插在最前面则原改变次数应为
j
−
1
j-1
j−1
所以
f
i
,
j
=
f
i
−
1
,
j
∗
(
i
−
1
)
+
f
i
−
1
,
j
−
1
f_{i,j}=f_{i- 1,j}*(i-1)+f_{i-1,j-1}
fi,j=fi−1,j∗(i−1)+fi−1,j−1
其实就是第一类斯特林数的递推公式
提前预处理一下即可做到
n
2
n^{2}
n2
100 100 100分解法
仍然是
D
P
DP
DP,原来的是把问题拆开,好做但是不能直接算
不妨大胆一点,设
f
i
f_i
fi表示长度为
i
i
i的答案
仍然考虑从
i
−
1
i-1
i−1转移过来
还是上面那句
考虑把最大的
i
i
i插入到长度为
i
−
1
i-1
i−1的改变次数为
j
j
j的排列中,则有
i
i
i个空可以插,其中最前面的空插进去会使改变次数加一,所以有
i
−
1
i-1
i−1个空使改变次数不变
f
i
=
f
i
−
1
∗
(
i
−
1
)
+
插到最前面的贡献
f_i=f_{i-1}*(i-1)+插到最前面的贡献
fi=fi−1∗(i−1)+插到最前面的贡献
考虑插在最前面,原本的改变次数为
x
x
x的都变为
x
+
1
x+1
x+1了
也就是
x
2
−
>
(
x
+
1
)
2
=
x
2
+
2
x
+
1
x^2 -> (x+1)^2=x^2+2x+1
x2−>(x+1)2=x2+2x+1
我们设
g
i
g_i
gi表示原本算贡献时是按照
x
x
x来算的长度为
i
i
i的答案
对于那个
1
1
1,因为插在最前面后面的
i
−
1
i-1
i−1个数共有
(
i
−
1
)
!
(i-1)!
(i−1)!种组合
所以
f
i
=
f
i
−
1
∗
(
i
−
1
)
+
f
i
−
1
+
2
g
i
−
1
+
(
i
−
1
)
!
=
f
i
−
1
∗
i
+
(
i
−
1
)
!
f_i=f_{i-1}*(i-1)+f_{i-1}+2g_{i-1}+(i-1)!=f_{i-1}*i+(i-1)!
fi=fi−1∗(i−1)+fi−1+2gi−1+(i−1)!=fi−1∗i+(i−1)!
g
i
g_i
gi同样这么推
g
i
=
g
i
−
1
∗
i
+
(
i
−
1
)
!
g_i=g_{i-1}*i+(i-1)!
gi=gi−1∗i+(i−1)!
C o d e \mathcal{Code} Code
/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月28日 星期六 09时34分38秒
*******************************/
#include <cstdio>
#include <fstream>
using namespace std;
const int maxn = 100005;
const int mod = 998244353;
//{{{cin
struct IO{
template<typename T>
IO & operator>>(T&res){
res=0;
bool flag=false;
char ch;
while((ch=getchar())>'9'||ch<'0') flag|=ch=='-';
while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
if (flag) res=~res+1;
return *this;
}
}cin;
//}}}
int T,n;
int f[maxn],g[maxn],fac[maxn];
int main()
{
fac[0]=1;
for (int i=1;i<=100000;++i){
fac[i]=1ll*fac[i-1]*i%mod;
f[i]=((1ll*f[i-1]*i%mod+2ll*g[i-1]%mod)%mod+fac[i-1])%mod;
g[i]=(1ll*g[i-1]*i%mod+fac[i-1])%mod;
}
cin>>T;
while (T--){
cin>>n;
printf("%d\n",f[n]);
}
return 0;
}
如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧