CF1809G prediction - dp - 组合数学 -
题目链接:https://codeforces.com/contest/1809/problem/G
题解:
一道很强的 dp
首先翻译条件:predictable 是什么意思?发现就是对每一个下标,前缀 max 和下一个位置至少差一个
看到 ,可以猜测最后应该是线性的,考虑线性 dp
设 表示已经选了前 大 rating 的人,并且第一个位置填的数不能和剩下没选的人冲突,这里“冲突”指的是
为什么要这么设状态?因为我们不可能再设一维状态来表示前缀 max,因此我们需要确保每一次转移的时候都转移到合法状态
假设现在已经填了前 大的数,那么第 个数有以下两种填法:
- 填在第 个数的后面,那么显然这个状态一定合法(开头的数没有变),转移为
- 填在第 个数前面(即放在开头),那么和当前数冲突的数字(必然是 连续的一段)应该也一块放,这样保证状态还是合法的。考虑先放第 ,有 种方法(放在第 的后面),再放 ,有 种……最后再放开头的 ,转移为
代码:
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back
using namespace std;
typedef long long ll;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1e6+5, mod = 998244353;
int n,k,a[maxn],dp[maxn];
int fac[maxn], inv[maxn], to[maxn];
int pw(int x,int y){
if(!y)return 1;
if(y==1)return x;
int mid=pw(x,y>>1);
if(y&1)return 1ll*mid*mid%mod*x%mod;
return 1ll*mid*mid%mod;
}
int que(int l,int r){
return 1ll*fac[r]*inv[l-1]%mod;
}
signed main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
reverse(a+1,a+n+1);
for(int i=1, j=1;i<=n;i++){
while(j <= n && a[i] - a[j] <= k)++ j;
to[i] = j;
}
fac[0] = inv[0] = 1;
for(int i=1;i<=n;i++)fac[i] = 1ll*fac[i-1]*i%mod;
inv[n] = pw(fac[n], mod-2);
for(int i=n-1;i>=1;i--)inv[i] = 1ll*inv[i+1]*(i+1)%mod;
if(a[1] - a[2] > k)dp[1] = 1;
for(int i=1;i<n;i++){
// (i+2) .. (to[i]-1)
// if(to[i+1]-1 > i+1)
(dp[to[i+1]-1] += 1ll*dp[i]*que(i, to[i+1]-3)%mod) %= mod;
(dp[i+1] += 1ll*dp[i]*i%mod) %= mod;
}
printf("%d\n",dp[n]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示