本题定义dp[i][j]表示到达第 i 个石子左边 j 单位的位置,一大坨分讨状态转移,加上同余最短路即可 AC,建议添加标签"最短路""图论建模"
code:
#include<bits/stdc++.h>
using namespace std;
int n,len,l,r,dp[110][25],place[110];
map<int,int>stone;
int dis[25],ans;
struct EDGE{int to,val;};
vector<EDGE>edge[25];
void dj(){
priority_queue<pair<int,int>>q;
dis[0]=0;
q.push(make_pair(0,0));
while(q.size()){
int now=q.top().second;q.pop();
for(auto i : edge[now]){
int v=i.to;
int w=i.val;
if(dis[v]>dis[now]+w){
dis[v]=dis[now]+w;
q.push(make_pair(-dis[v],v));
}
}
}
return;
}
signed main(){
// freopen("river1.in","r",stdin);
cin>>len>>l>>r>>n;ans=n;
for(int i=1;i<=n;++i)cin>>place[i];
sort(place+1,place+1+n);place[0]=0;
for(int i=1;i<=n;++i)stone[place[i]]++;
for(int i=0;i<=n+1;++i)
for(int k=0;k<=r;++k)
dp[i][k]=n;
dp[0][0]=0;
place[n+1]=len;
for(int i=0;i<r;++i)dis[i]=1e9;
for(int i=0;i<r;++i){
for(int j=l;j<=r;++j){
int to=(i+j)%r;
edge[i].push_back({to,j});
}
}
dj();
for(int i=1;i<=n+1;++i){
//左边->左边/中间
for(int j=r;j>=0;--j){
for(int jump=l;jump<=r;++jump){
if(jump>j)continue;
if(jump==j)dp[i-1][0]=min(dp[i-1][0],dp[i-1][j]+stone[place[i-1]]);
else dp[i-1][j-jump]=min(dp[i-1][j-jump],dp[i-1][j]);
}
}
//左边/中间->右边->下一个
for(int j=r;j>=0;--j){
for(int jump=l;jump<=r;++jump){
if(jump<=j)continue;
int nxt=place[i-1]-j+jump;
int tot=i;
while(place[tot]<nxt&&tot<=n)tot++;
if(tot==n+1&&place[n+1]<=nxt){
ans=min(ans,dp[i-1][j]);
}
else if(place[tot]==nxt){
dp[tot][0]=min(dp[tot][0],dp[i-1][j]+stone[place[tot]]);
}
else{
for(int to=0;to<=r;++to){
int rest=place[tot]-to-nxt;
if(dis[rest%r]>rest)continue;
if(to==0)dp[tot][to]=min(dp[tot][to],dp[i-1][j]+stone[place[tot]]);
else dp[tot][to]=min(dp[tot][to],dp[i-1][j]);
}
}
}
}
}
for(int i=r-1;i>=0;--i)ans=min(ans,dp[n+1][i]);
cout<<ans;
return 0;
}