题解:P9823 [ICPC 2020 Shanghai R] The Journey of Geor Autumn
违规用户名1010570 · · 题解
关键观察
特殊情况分析:当
最小值位置限制:对于
动态规划设计
定义状态:\
设
两边除以
滑动窗口优化:\
为了高效计算
时间复杂度与空间复杂度:\
时间复杂度:
代码实现详解
#include<bits/stdc++.h>
#define int long long
#define modd 998244353
using namespace std;
int n,k,t;
int dp[10000005];// dp[i] = f(i)/i!
int inv[10000005];// 逆元数组,用于计算除法
signed main(){
cin>>n>>k;
t=1;
inv[1]=1;
// 预处理阶乘t = n! 和逆元inv[i]
for(int i=2;i<=n;i++){
t=t*i%modd; // 计算阶乘n!
// 线性求逆元:inv[i] = modd - modd/i * inv[modd%i] % modd
inv[i]=modd-modd/i*inv[modd%i]%modd;
}
// 特殊情况:k >= n时,所有排列都是好排列
if(k>=n){
cout<<t;
return 0;
}
// 初始化:i <= k时,dp[i] = 1
for(int i=0;i<=k;i++){
dp[i]=1;
}
// sum维护最近k个dp值的和,初始为dp[1]+dp[2]+...+dp[k] = k
int sum=k;
for(int i=k+1;i<=n;i++){
// dp[i] = sum / i,用逆元实现除法
dp[i]=sum*inv[i]%modd;
// 滑动窗口更新:加入新元素dp[i],移除过期元素dp[i-k]
sum=(sum+dp[i]-dp[i-k]+modd)%modd;
}
// 最终答案为f(n) = dp[n] * n!
int ans=dp[n]*t%modd;
cout<<ans;
return 0;
}
//For The Greater Good