题目描述
在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
输入输出格式
输入格式:
输入文件river.in的第一行有一个正整数L(1 <= L <= 10^9),表示独木桥的长度。第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中1 <= S <= T <= 10,1 <= M <= 100。第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。
输出格式:
输出文件river.out只包括一个整数,表示青蛙过河最少需要踩到的石子数。
输入输出样例
输入样例#1: 复制
10
2 3 5
2 3 5 6 7
输出样例#1: 复制
2
解析:
语文理解好一点,不是必须踩着石头过河,是尽量少的踩石头!!!
dp[i]代表距离起点为i走的最少石头数
状态转移方程:
dp[i]=min(dp[i],dp[j]+stone[i]);
但是这里距离太大,而且十分离散
所以这里需要路径压缩
选取lcd(9,10)=90这个数,为什么?
需要用到扩展欧几里得:
把题目转化为:
二元一次不定方程:ax+by=c, 且gcd(a,b)=1 (a,b为两种步数走法,c为达到距离)(x,y为用a,b这两种步数的次数)
证明存在(x,y)的非负整数解的c的最小值为lcm(a,b)=ab
证明:
x的通解 x=x0+bt(t>=0且为整数)
这里我们不妨设x0=0(取最小的那个特解)
1.当x!=0时:
x=bt(t>=1且t为整数)
所以 x>=b
所以 c>=ax>=ab
2.当x==0时
则by=c
则存在当y>=a时,可以满足c>=ab成立
综上:当c=ab时,方程总是存在非负整数解
所以对于这题来说,只要取两个不同最大步数9,10处理,可得90为最小值
#include<bits/stdc++.h>
using namespace std;
#define maxn 40000
typedef long long ll;
#define inf 9999999999
#define ri register int
#define getchar() (Ss==Tt&&(Tt=(Ss=BB)+fread(BB,1,1<<15,stdin),Ss==Tt)?EOF:*Ss++)
char BB[1 << 18], *Ss = BB, *Tt = BB;
inline int read()
{
int x=0;
int ch=getchar(),f=1;
while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
if (ch=='-')
{
f=-1;
ch=getchar();
}
while (isdigit(ch))
{
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
int n;
int s,t;
int L,m;
int a[maxn];
int b[maxn];
int ans=0;
int dp[maxn];
int main()
{
// freopen("test.txt","r",stdin);
memset(dp,0x3f,sizeof(dp));
L=read();
L=0;
s=read(),t=read(),m=read();
if(s==t)
{
int x;
for(int i=1; i<=m; i++)
{
x=read();
if(x%s==0)ans++;
}
cout<<ans;
return 0;
}
for(int i=1; i<=m; i++)
b[i]=read();
sort(b+1,b+m+1);
for(int i=1; i<=m; i++)
{
int x=b[i]-b[i-1];
if(x>90)L+=90;
else L+=x;
a[L]=1;
}
for(int i=s; i<=t; i++)
dp[i]=a[i]?1:0;
for(int i=t+1; i<=L+t; i++)
for(int j=i-t; j<=i-s; j++)
{
if(j<0)continue;
dp[i]=min(dp[i],dp[j]+(a[i]?1:0));
}
ans=inf;
for(int i=L; i<=L+t; i++)
ans=min(ans,dp[i]);
cout<<ans;
return 0;
}