洛谷1052——过河(DP+状态压缩)

题目描述

在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,…,L0,1,…,L0,1,,L(其中LLL是桥的长度)。坐标为000的点表示桥的起点,坐标为LLL的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是SSSTTT之间的任意正整数(包括S,TS,TS,T)。当青蛙跳到或跳过坐标为LLL的点时,就算青蛙已经跳出了独木桥。

题目给出独木桥的长度LLL,青蛙跳跃的距离范围S,TS,TS,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。

输入输出格式

输入格式:

第一行有111个正整数L(1≤L≤109)L(1 \le L \le 10^9)L(1L109),表示独木桥的长度。

第二行有333个正整数S,T,MS,T,MS,T,M,分别表示青蛙一次跳跃的最小距离,最大距离及桥上石子的个数,其中1≤S≤T≤101 \le S \le T \le 101ST10,1≤M≤1001 \le M \le 1001M100

第三行有MMM个不同的正整数分别表示这MMM个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。

输出格式:

一个整数,表示青蛙过河最少需要踩到的石子数。

输入输出样例

输入样例#1:

10
2 3 5
2 3 5 6 7

输出样例#1:

2

说明

对于30%的数据,L≤10000L \le 10000L10000

对于全部的数据,L≤109L \le 10^9L109

2005提高组第二题

思路

如果不考虑数据范围的话,可以很快得出递推关系式:dp[i]=min(dp[i+k]+a[i])  (S≤k≤T)dp[i]=min(dp[i+k]+a[i])\ \ (S\leq k \leq T)dp[i]=min(dp[i+k]+a[i])  (SkT)a[i]a[i]a[i]iii点的石头数dp[i]dp[i]dp[i]表示到达iii点踩到的最少石头数)

然鹅看了数据范围后,时间和空间都是过不去的。所以需要选择别的方法:

  • S=TS=TS=T的时候,可以很容易得到:所有在SSS倍数位置上的点,都会走到,所以对该种情况进行特判

  • 我们可以发现石子在桥上放置的是非常稀疏的,而且当点的位置超过一定范围,点都是可以跳到的。所以可以将石子所在的位置压缩到这个范围里去。将压缩后位置储存起来作为新的石头的位置,按照这个位置进行dp即可

假设每次走ppp或者p+1p+1p+1步.我们知道gcd(p,p+1)=1gcd(p,p+1)=1gcd(p,p+1)=1.
由扩展欧几里得可知,对于二元一次方程组:
px+(p+1)y=gcd(p,p+1)px+(p+1)y=gcd(p,p+1)px+(p+1)y=gcd(p,p+1)是有整数解的,即可得:px+(p+1)y=spx+(p+1)y=spx+(p+1)y=s是一定有整数解的。
px+(p+1)y=spx+(p+1)y=spx+(p+1)y=s的解为:x=x0+(p+1)t,y=y0−ptx=x_0+(p+1)t,y=y_0−ptx=x0+(p+1)t,y=y0pt。令0≤x≤p0\leq x\leq p0xp(通过增减tttp+1p+1p+1来实现),s>p×(p+1)−1s>p\times (p+1)−1s>p×(p+1)1
则有:y=s−pxp+1≥s−p2p+1>p(p+1)−1−pxp+1≥0y=\dfrac {s-px}{p+1}\geq \dfrac {s-p^{2}}{p+1} >\dfrac {p\left( p+1\right) -1-px}{p+1}\geq 0y=p+1spxp+1sp2>p+1p(p+1)1px0
即表示,当s≤p×(p+1)s\leq p\times (p+1)sp×(p+1)时,px+(p+1)y=spx+(p+1)y=spx+(p+1)y=s有两个非负整数解,每次走ppp步或者p+1p+1p+1步,p×(p+1)p\times (p+1)p×(p+1)之后的地方均能够到达。
如果两个石子之间的距离大于p×(p+1)p\times (p+1)p×(p+1),那么就可以直接将他们之间的距离更改为p×(p+1)p \times (p+1)p×(p+1)
综上,得到压缩路径的方法:若两个石子之间的距离大于t×(t−1)t\times(t−1)t×(t1),则将他们的距离更改为t×(t−1)t\times (t−1)t×(t1)

为t≤10为t\leq10t10,因此我们可以直接将大于10×910\times910×9的距离直接化为909090.

关于路径压缩常数的选择,证明过程详见:https://blog.csdn.net/qq_34940287/article/details/77494073

AC代码

/*************************************************************************

	 > Author: WZY
	 > School: HPU
	 > Created Time:   2019-02-03 15:55:49
	 
************************************************************************/
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define ms(a,b) memset(a,b,sizeof(a))
#define INF 0x7f7f7f7f
const int maxn=1e6+10;
const int mod=1e9+7;
using namespace std;
int a[maxn];
int dp[maxn];
int vis[maxn];
int main(int argc, char const *argv[])
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int L;
	int ans=0;
	int s,t,m;
	cin>>L;
	cin>>s>>t>>m;
	for(int i=1;i<=m;i++)
		cin>>a[i];
	if(s==t)
	{
		for(int i=1;i<=m;i++)
		{
			if(a[i]%s==0)
				ans++;
		}
		cout<<ans<<endl;
		return 0;
	}
	sort(a+1,a+1+m);
	int _=90;
	int res=a[1]%_;
	vis[res]=1;
	// 缩点
	for(int i=2;i<=m;i++)
	{
		res+=(a[i]-a[i-1])%_;
		vis[res]=1;
	}
	for(int i=res;i>=0;i--)
	{
		dp[i]=INF;
		for(int j=s;j<=t;j++)
			dp[i]=min(dp[i],dp[i+j]+vis[i]);
	}
	cout<<dp[0]<<endl;
	return 0;
}

转载于:https://www.cnblogs.com/Friends-A/p/11054978.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值