PS:如果读过题了可以跳过题目描述直接到题解部分
提交链接:洛谷 T284709 怨念(resent)
题目
题目背景
“结束了。”dlh眼睁睁地看着右下角的时间到达13:00。屏幕上只留下一个
O
(
n
2
)
O(n^2)
O(n2) 的暴力。
这场考试成为了dlh的心理阴影,所以他今天要滥用出题人的权力,将这一不美好的回忆强加于你。
题目描述
现在你被迫解决根据dlh转化错的题意出的题:给定整数
n
,
k
n,k
n,k,对于每个
i
∈
[
1
,
n
]
i\in[1,n]
i∈[1,n],求满足下列条件的
整数数列
a
a
a 权值之和:
数列长度
∣
a
∣
=
i
|a|=i
∣a∣=i ,元素大小均在
[
1
,
n
]
[1,n]
[1,n] 中,且
a
a
a 中没有相同元素。
一个数列
a
a
a 的权值定义为
Π
i
=
1
∣
a
∣
k
a
i
\Pi _{i=1}^{|a|}k^{a_i}
Πi=1∣a∣kai。
答案对
998244353
998244353
998244353 取模。
输入格式
一行两个正整数 n , k n,k n,k。
输出格式
n n n 行,第 i i i 行一个正整数,表示 ∣ a ∣ = i |a|=i ∣a∣=i 时的答案。
样例 #1
样例输入 #1
3 3
样例输出 #1
39
702
4374
样例 #2
样例输入 #2
20 4
样例输出 #2
592793496
665177021
954073671
15970570
751832606
243984599
387448346
418729740
223224628
604189073
211339162
523261611
196916730
586763100
706792305
194432676
664618102
203112049
922150155
823565468
提示
样例1解释
以长度
i
=
2
i=2
i=2 为例,合法序列有
[
1
,
2
]
,
[
1
,
3
]
,
[
2
,
3
]
,
[
2
,
1
]
,
[
3
,
1
]
,
[
3
,
2
]
[1,2],[1,3],[2,3],[2,1],[3,1],[3,2]
[1,2],[1,3],[2,3],[2,1],[3,1],[3,2],权值分别为
27
,
81
,
243
,
27
,
81
,
243
27,81,243,27,81,243
27,81,243,27,81,243,和为
702
702
702。
数据范围与提示
对于前 10 % 10\% 10% 的数据, n ≤ 20 n\le20 n≤20。
对于前 40 % 40\% 40% 的数据, n ≤ 5000 n\le5000 n≤5000。
对于前 70 % 70\% 70% 的数据, n ≤ 2 16 n\le 2^{16} n≤216。
对于所有的数据, 1 ≤ n ≤ 5 × 1 0 6 , 0 < k < 998244353 1\le n\le 5\times 10^6,0<k<998244353 1≤n≤5×106,0<k<998244353
题解
代码实现
100pts
//洛谷 T284709 怨念(resent)
#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
using namespace std;
const int mo=998244353;
long long n,k,m;
long long p[5000010];//k^i
long long ikni;//inv(k^(n*i))
long long ikn;//inv(k^n)
long long kii;//k^(i*i)
long long iki;//inv(k^i)
long long ik;//inv(k)
long long a[5000010];//i!
long long b[5000010];//k^i-1的前缀积
long long ib[5000010];//k^i-1的逆元
long long so=1,ma=1;
void in(long long &x){
int nt;
x=0;
while(!isdigit(nt=getchar()));
x=nt^'0';
while(isdigit(nt=getchar())){
x=(x<<3)+(x<<1)+(nt^'0');
}
}
long long mi(long long x,long long y){
long long ans=1;
while(y){
if(y&1){
ans=(ans*x)%mo;
}
x=(x*x)%mo;
y>>=1;
}
return ans;
}
int main(){
in(n),in(k);
k=mi(k,mo-2);
ik=mi(k,mo-2);
p[0]=1;
a[0]=1;
b[0]=1;
for(m=1;m<=n;++m){
p[m]=p[m-1]*k%mo;
b[m]=(b[m-1]*(p[m]-1))%mo;
a[m]=a[m-1]*m%mo;
}
ikn=mi(p[n],mo-2);
ib[n]=mi(b[n],mo-2);
for(m=n-1;m>=1;--m){
ib[m]=ib[m+1]*(p[m+1]-1)%mo;
}
for(m=1;m<=n;++m){
ib[m]=ib[m]*b[m-1]%mo;
}
//给ib赋值
ikni=1;
kii=1;
iki=1;
for(m=1;m<=n;++m){
ikni=ikni*ikn%mo;
so=so*(p[n]-p[m-1])%mo;//累计分子
ma=ma*iki%mo*ib[m]%mo;//累计分母
iki=iki*ik%mo;
printf("%lld\n",(so*ma%mo*ikni%mo*kii%mo+mo)*a[m]%mo);
kii=kii*p[m]%mo;
}
return 0;
}