题目链接
看完题目后,显然想到动态规划,考虑对于桥上的每一位进行动态规划,对于
f
[
i
]
f[i]
f[i]从
f
[
i
−
t
]
∼
f
[
i
−
s
]
f[i-t]\sim f[i-s]
f[i−t]∼f[i−s]找一个最小值
k
k
k,如果第
i
i
i位为石头,则
f
[
i
]
=
k
+
1
f[i] = k + 1
f[i]=k+1 否则
f
[
i
]
=
k
f[i]= k
f[i]=k
但是一看数据范围桥长
1
0
9
10^9
109寄
再往后看,石头
≤
100
\le100
≤100
分析题目,如果两块石头间的距离大于
l
c
m
(
s
,
t
)
lcm(s,t)
lcm(s,t)则可以把两块石头间的距离减去
l
c
m
(
s
,
t
)
lcm(s,t)
lcm(s,t)的倍数直至两块石头间距离
≤
l
c
m
(
s
,
t
)
\le lcm(s,t)
≤lcm(s,t),这样可以把桥长缩短到
1000
1000
1000再使用动态规划
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int gcd(int a,int b){
int c = a % b;
while(c != 0){
a = b;
b = c;
c = a % b;
}
return b;
}
int main(){
const int MAXN = 10010;
int L,s,t,m,a = 0;
int stone[MAXN],f[MAXN],map[MAXN];
scanf("%d%d%d%d",&L,&s,&t,&m);
for(int i = 1; i <= m; i ++)
scanf("%d",&stone[i]);
if(s < t){
int k = s * t / gcd(s,t);
sort(stone + 1,stone + m + 1);
stone[0] = 0;
memset(map,0,sizeof(map));
for(int i = 1; i <= m; i++){
if(stone[i] - stone[i - 1] > k)a = a + (stone[i] - stone[i - 1]) % k + k;
else a = a + (stone[i] - stone[i - 1]) % k;
map[a] = 1;
}
if(L - stone[m] > k) L = a + (L - stone[m]) % k + k;
else L = a + (L - stone[m]) % k;
memset(f,0x7f,sizeof(f));
f[0] = 0;
for(int i = 1; i <= L; i ++){
for(int j = s; j <= t; j ++)
if(i - j >= 0) f[i] = min(f[i],f[i - j]);
if(map[i]) f[i] ++;
}
int ans = 0x7f;
for(int i = a; i <= L; i ++)
ans = min(ans,f[i]);
printf("%d",ans);
}
else {
int ans = 0;
for(int i = 1; i <= m; i ++)
if(stone[i] % s == 0) ans ++;
printf("%d",ans);
}
return 0;
}