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";
}

 

posted on 2022-05-29 16:14  zesure  阅读(47)  评论(0编辑  收藏  举报

导航