题目链接
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?
- 1 ≤ A i ≤ M ( 1 ≤ i ≤ N ) 1≤A_i ≤M (1≤i≤N) 1≤Ai≤M(1≤i≤N)
- ∣ A i − A i + 1 ∣ ≥ K ( 1 ≤ i ≤ N − 1 ) ∣A_i −A _{i+1} ∣≥K (1≤i≤N−1) ∣Ai−Ai+1∣≥K(1≤i≤N−1)
Since the count can be enormous, find it modulo 998244353 998244353 998244353.
Constraints
- 2 ≤ N ≤ 1000 2≤N≤1000 2≤N≤1000
- 1 ≤ M ≤ 5000 1≤M≤5000 1≤M≤5000
- 0 ≤ K ≤ M − 1 0≤K≤M−1 0≤K≤M−1
All values in input are integers.
Input
Input is given from Standard Input in the following format:
N M K
Output
Print the count modulo 998244353 998244353 998244353.
Sample Input 1
2 3 1
Sample Output 1
6
The following 6 6 6 sequences satisfy the conditions.
- ( 1 , 2 ) (1,2) (1,2)
- ( 1 , 3 ) (1,3) (1,3)
- ( 2 , 1 ) (2,1) (2,1)
- ( 2 , 3 ) (2,3) (2,3)
- ( 3 , 1 ) (3,1) (3,1)
- ( 3 , 2 ) (3,2) (3,2)
Sample Input 2
3 3 2
Sample Output 2
2
The following 2 2 2 sequences satisfy the conditions.
- ( 1 , 3 , 1 ) (1,3,1) (1,3,1)
- ( 3 , 1 , 3 ) (3,1,3) (3,1,3)
Sample Input 3
100 1000 500
Sample Output 3
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 <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cstring>
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;
}