建议添加算法标签
查看原帖
建议添加算法标签
1164775
Jadonyzx楼主2024/10/20 20:13

本题定义dp[i][j]表示到达第 ii 个石子左边 jj 单位的位置,一大坨分讨状态转移,加上同余最短路即可 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;
}
2024/10/20 20:13
加载中...