思路
-
n
=
1
n=1
n=1 时有
m
+
2
m+2
m+2 种取值,直接输出答案
m
+
2
m+2
m+2 即可,
虽然不知道题目搞这个分类有啥用。 - n > 1 n>1 n>1 时,需要考虑题中要求:两个互为相反顺序的序列记为相同,开始容易想到将全部随意排列的总情况数直接除以 2 2 2,但是这样对本身是回文的序列进行了错误的计数,因为回文的序列反过来为本身,并不会使情况数减少,所以答案为非回文序列的情况数除以 2 2 2 加上回文序列的情况数。
先算出回文序列的情况数(直接对序列的一半计数,另一半可以直接对应): ( m + 1 ) × m ⌈ n 2 ⌉ − 1 (m+1) \times m^{ \lceil \frac{n}{2}\rceil -1} (m+1)×m⌈2n⌉−1。
- 为什么 n 2 \frac{n}{2} 2n 要向上取整?如果序列长度为奇数,则中间的位置的情况也要计数,序列长度为偶数,则直接计算一半即可。
而直接使用乘法原理,把每一位的情况数相乘,得出全部随意排列的总情况数为 ( m + 1 ) ( m + 1 ) × m n − 2 (m+1)(m+1) \times m^{n-2} (m+1)(m+1)×mn−2。
所以直接根据上面的分析表示出答案为 ( m + 1 ) ( m + 1 ) × m n − 2 − ( m + 1 ) × m ⌈ n 2 ⌉ − 1 2 + ( m + 1 ) × m ⌈ n 2 ⌉ − 1 \frac{(m+1)(m+1) \times m^{n-2}-(m+1) \times m^{ \lceil \frac{n}{2}\rceil -1}}{2}+(m+1) \times m^{ \lceil \frac{n}{2}\rceil -1} 2(m+1)(m+1)×mn−2−(m+1)×m⌈2n⌉−1+(m+1)×m⌈2n⌉−1。
注意本题需要取模,而式子出现了除法,需要先通过费马小定理(模数是质数故可以使用)计算 2 2 2 在模 998244353 998244353 998244353 意义下的逆元。
使用快速幂计算,总复杂度为 O ( T log n ) O(T \log n) O(Tlogn)。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#define ull unsigned long long//注意数据范围
using namespace std;
const ull Mod=998244353;
ull n,m,t;
ull qpow(ull a,ull p)//快速幂
{
ull ans=1;
while(p)
{
if(p&1) ans=ans*a%Mod;
a=a*a%Mod;
p>>=1;
}
return ans;
}
const ull inv=qpow(2,Mod-2)%Mod;//2在模998244353意义下的逆元
int main()
{
scanf("%llu",&t);
while(t--)
{
scanf("%llu%llu",&n,&m);
ull res;
if(n==1) res=m+2;//特判
else res=(((m+1)%Mod*(m+1)%Mod*qpow(m,n-2)%Mod+Mod-(m+1)%Mod*qpow(m,(n+1)/2-1)%Mod)*inv%Mod+(m+1)%Mod*qpow(m,(n+1)/2-1)%Mod)%Mod;
printf("%llu\n",res);
}
return 0;
}