原题链接:http://210.44.14.31/problem/show/1087
假设s=4,t=5
有图易知,在s*t后的位置都可到达。
因此,我们可以将无石子长度大于s*t的部分压缩为 s*t 。
状态转移方程:
F[ i ]=min( F[ i ] , F[ j ] )
j的范围: i - T<= j <= i-S
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int main()
{
int L,S,T,M;
int stone[100 + 5]; //记录原来石子的位置
int stonepos[10000 + 10]; //记录压缩后石子的位置
int f[10000 + 10]; //dp
int ans = 200;
memset(stonepos, 0, sizeof(stonepos));
cin >> L >> S >> T >> M;
for (int i = 1; i <= M; i++)
cin >> stone[i];
if (S != T)
{
sort(stone + 1, stone + M + 1);
stone[0] = 0;
int dis, pos = 0; //dia记录相邻两点的距离 pos表示已经处理到位置
for (int i = 1; i <= M; i++)
{
dis = stone[i] - stone[i - 1];
if (dis<=S*T) //小于压缩值时,按原值处理
pos += dis;
else
pos += T*S;
stonepos[pos] ++; //有石子的位置
}
f[0] = 0;
for (int i = 1; i < pos + T; i++) //pos+T 而不是L 很好理解!
{
f[i] = 200;
for (int j = i - T; j <= i - S; j++) //能跳到 i 点前的最小值
if (j >= 0)
f[i] = min(f[j], f[i]);
f[i] += stonepos[i]; //再加上该点石子的数量
if (i > pos) //找跳过最后一个石子 所踩石子最小的值。
ans = min(f[i], ans);
}
}
else //S==T时
{
ans = 0;
for (int i = 1; i <= M;i++)
if (stone[i] % S == 0)
ans++;
}
cout << ans ;
return 0;
}