悬关
  • 板块题目总版
  • 楼主ZhuYF1029
  • 当前回复10
  • 已保存回复10
  • 发布时间2023/8/2 12:26
  • 上次更新2023/11/3 06:23:22
查看原帖
悬关
802655
ZhuYF1029楼主2023/8/2 12:26

从前有一个神奇的OJ

上面有一道神奇的线性DP题

题目描述:

有n 个俄罗斯套娃,n 个套娃的大小从小到大分别为 a1,a2,...,an。在俄罗斯套娃中,相邻两个套娃之间的大小差至少为 r。准确地讲,一个套娃 河以被套在另一个套娃j里面,当且仅当它们的大小满足 ai+r<=aj。 你希望把 n 个套娃分成k组,每组的所有套娃都可以按”一个套一个”的形式套成一堆组由编号分别为 c1,C2,...,cm(1 < c < c2 <...< cm n)组成的套娃可以套成一堆,当且仅当所有的 1<i<m, a[i]+r<=a[i+1] 你想知道有多少种方式,将套娃分成k组,每组都能被套成一堆。答案对998244353取模。 Note: {1,2,3,4和3,4,1,2被认为是一种方式。 输入格式 第一行输入三个整数n,k,r(1 <=k<=n<=5000,1<=r<=10^9,分别表示套娃的个数,需要分成的堆数,以及相邻套娃之间需满足的大小差 第二行输入n 个整数 al,a2,...,an (1 < a a2 ...< an < 10,表示n个套娃的大小。 输出格式 一行一个正整数,表示方案数对998244353 取模后的答案

样例1:

4 3 2

1 2 3 4

输出:

3

样例2:

4 2 1

1 1 2 2

输出:

2

然后,我灵感打发 写道:

//code by Hacker Zhu Yifan
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int n,k,r;
bool now=0,last=1;
vector<int> val,dp[2];
signed main(void){
    cin >> n >> k >> r;
    val.assign(n,0);
    for(int i=0;i<n;i++){
        cin >> val[i];
    }
    dp[now].resize(1,1);
    for(int i=0;i<n;i++){
        now=!now,last=!last;
        dp[now].assign(min(i+1,k)+1,0);
        int cnt=0;
        for(int j=0;j<i;j++){
            cnt+=(val[j]+r>val[i]);
        }
        for(int j=0;j<=min(i+1,k);j++){
            if(j>0) dp[now][j]=(dp[now][j]%mod+dp[last][j-1]%mod)%mod;
            if(j<dp[last].size()) dp[now][j]=(dp[now][j]%mod+(max((int)0,j-cnt)%mod)*(dp[last][j]%mod))%mod;
        }
    }
    cout << dp[now][k] << endl;
    return 0;
}

然后就开门红了

2023/8/2 12:26
加载中...