atcode abc E - Distance Sequence
题意:给定三个数N,M,K
N为序列长度,M为每个序列的大小,K为每个序列与后一个序列差值的绝对值
求这种序列组合数
思路:
典中典dp求组合数,但我一直都没怎么刷过dp,,,,
首先考虑dp数组状态
根据题目,状态转移是根据序列某个位置与下一个位置的差值决定的
那么假设:dp[i][j],i为序列所在的位置,j为数列长度
讨论第一维,dp[i]必然由dp[i-1]这个状态转移而来
对于第二维,dp[i][j]由dp[i-1][m]转移过来,m是所有与j相减大于等于K的数
但这样复杂度就是N*(M^2),纯纯的超时
这里我们可以分析,m是一个连续的区域,那么利用前缀和的思想,可以达成o1级别的查询
再考虑一下初始状态dp[1][j]全部赋值成1
但接下来你就会发现
wa了
还需要特判k=0的情况,这时候每一位xjb取就行
#include<iostream> #include<map> #include<set> #include<algorithm> #include<unordered_map> typedef long long ll; typedef unsigned long long ull; const ull base=131; #define MAX 50009 #define PI 3.141592653589793 #define mod 998244353 using namespace std; ll dp[1009][MAX]; ll pre[1009][MAX]; int main() { std::ios::sync_with_stdio(false); std::cin.tie(0);std::cout.tie(0); int n,m,k;cin>>n>>m>>k; for(int i=1;i<=m;i++) dp[1][i]=1; for(int i=1;i<=m;i++) pre[1][i]=(pre[1][i-1]+dp[1][i])%mod; if (k==0){ ll ans=1; for (int i=1;i<=n;i++) ans=(ans*m)%mod; cout<<ans<<endl; return 0; } for(int i=2;i<=n;i++){ for(int j=1;j<=m;j++){ int l=j-k; int r=j+k; if(r<=m) dp[i][j]=(dp[i][j]+pre[i-1][m]-pre[i-1][r-1]+mod)%mod; if(l>=0) dp[i][j]=(dp[i][j]+pre[i-1][l]+mod)%mod; } for(int j=1;j<=m;j++) pre[i][j]=(pre[i][j-1]+dp[i][j])%mod; } cout<<pre[n][m]<<"\n"; }