abc253 E - Distance Sequence
rating : 1073
How many integer sequences A = ( A 1 , … , A N ) A=(A_1 ,…,A_N) A=(A1,…,AN) of length N N N satisfy all the conditions below?
Since the count can be enormous, find it modulo 998244353 998244353 998244353.
All values in input are integers.
Input is given from Standard Input in the following format:
N M K
Print the count modulo 998244353 998244353 998244353.
2 3 1
6
The following 6 6 6 sequences satisfy the conditions.
3 3 2
2
The following 2 2 2 sequences satisfy the conditions.
100 1000 500
657064711
题目的大致意思是:要从 1 ∼ M 1 \sim M 1∼M 中选出 N N N 个数,这 N N N 个数的数列就为 A A A,这个数列 A A A 中每两个相邻的数的差的绝对值必须 大于等于 K K K, ∣ A i − A i + 1 ∣ ≥ K |A_i - A_{i+1}| \geq K ∣Ai−Ai+1∣≥K。
问一共有多少种方案。
我们定义 f ( i , j ) f(i,j) f(i,j) 为 考虑前 i i i 个数,并且最后一个数,也就是第 i i i 个数为 j j j 的方案数量。
按照定义最终我们返回的答案就是 ∑ j = 1 M f [ n ] [ j ] \sum_{j = 1}^{M}f[n][j] ∑j=1Mf[n][j]。
对于 f [ i ] [ j ] f[i][j] f[i][j], 一共有 { f [ i − 1 ] [ 1 ] , f [ i − 1 ] [ 2 ] , . . . , f [ i − 1 ] [ j − k ] } , { f [ i − 1 ] [ j + k ] , f [ i − 1 ] [ j + k + 1 ] , . . . , f [ i − 1 ] [ m ] } \{ f[i - 1][1],f[i-1][2],...,f[i-1][j-k]\} , \{f[i-1][j+k],f[i-1][j+k+1],...,f[i-1][m] \} {f[i−1][1],f[i−1][2],...,f[i−1][j−k]},{f[i−1][j+k],f[i−1][j+k+1],...,f[i−1][m]} 这些状态可以转移到 f [ i ] [ j ] f[i][j] f[i][j]。
也就是 f [ i ] [ j ] = ∑ 1 j − k f [ i − 1 ] [ j ] ( j > k ) + ∑ j + k m f [ i − 1 ] [ j ] ( j + k ≤ m ) f[i][j] = \sum_{1}^{j - k}f[i-1][j] (j > k) + \sum_{j + k}^{m}f[i-1][j] (j + k \leq m) f[i][j]=∑1j−kf[i−1][j](j>k)+∑j+kmf[i−1][j](j+k≤m)。
对于这两段连续的和,我们可以分别使用一个前缀和 p r e pre pre ,一个后缀和 s u f suf suf 数组来进行优化。
初始化: f [ 1 ] [ j ] = 1 ( 1 ≤ j ≤ m ) f[1][j] = 1 \quad (1 \leq j \leq m) f[1][j]=1(1≤j≤m),因为只考虑第一个数的时候,无论这个数是 1 ∼ M 1 \sim M 1∼M 中的哪一个数,都只存在一种方案。
时间复杂度: O ( M × N ) O(M \times N) O(M×N)
C++代码:
#include
#include
#include
#include
#include
#include
using namespace std;
using LL = long long;
const int N = 1010 , M = 5010, MOD = 998244353;
int n,m,k;
LL f[N][M];
LL pre[M] , suf[M];
void solve(){
cin>>n>>m>>k;
//初始化
for(int j = 1;j <= m;j++) f[1][j] = 1;
for(int i = 2;i <= n;i++){
//求前缀和数组 和 后缀和数组
for(int j = 1;j <= m;j++) pre[j] = (pre[j - 1] + f[i - 1][j]) % MOD;
for(int j = m;j >= 1;j--) suf[j] = (suf[j + 1] + f[i - 1][j]) % MOD;
//k > 0
if(k){
for(int j = 1;j <= m;j++){
if(j > k) f[i][j] = (f[i][j] + pre[j - k]) % MOD;
if(j + k <= m) f[i][j] = (f[i][j] + suf[j + k]) % MOD;
}
}
else{
for(int j = 1;j <= m;j++) f[i][j] = pre[m];
}
}
LL ans = 0;
for(int j = 1;j <= m;j++) ans = (ans + f[n][j]) % MOD;
cout<<ans<<'\n';
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","rt",stdin);
freopen("out.txt","wt",stdout);
#endif
int t = 1;
while(t--){
solve();
}
return 0;
}