您的位置:首页 > 其它

NOIP模拟17.9.22

2017-09-22 21:33 225 查看
[b]NOIP模拟17.9.22[/b]

前进!
【问题描述】
数轴的原点上有一只青蛙。青蛙要跳到数轴上≥ 𝐷的位置去,但很不幸数轴
上有𝑛个区间是禁区,不能进入。青蛙会选择一个长度𝐿,从原点开始每次向右
跳长度为𝐿的一段。一路上青蛙会停的位置是0, 𝐿, 2𝐿,…直到跳到了≥ 𝐷的位置,
任意一个位置都不能在禁区中。请求出𝐿的最小值,注意𝐿可以是实数。
【输入格式】
输入文件为susume.in。
输入文件的第一行包含两个整数𝑛和𝐷,含义如问题描述中所述。
接下来𝑛行,每行描述一个禁区。每行有两个整数𝑙和𝑟,代表数轴上(𝑙, 𝑟)的
区间是禁区。保证有0 ≤ 𝑙 < 𝑟 ≤ 𝐷。
【输出格式】
输出文件为susume.out。
输出一行,代表𝐿的最小值。精度要求请参考评分方法。
【样例输入1】
2 25
11 21
3 7
【样例输出1】
10.5
【样例1 解释】
第一步跳到了𝑥 = 10.5,第二步跳到𝑥 = 21,第三步就跳到了≥ 𝐷的位置。
可以证明这个解是最小的解。
【样例输入2】
2 100
0 50
50 100
【样例输出2】
50.0

[b]【题解】[/b]

考场上想出正解,但是因为SPJ所以没测

不难证明一定会在某次跳跃跳到某个区间的右端点

这样我们枚举是哪一个右端点,不断/2,/3,/4.../r作为

步长L。然后在On时间判断是否合法即可

挂标称了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(a) ((a) < 0 ? (-1 * (a)) : (a))

inline void read(int &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9')c = ch, ch = getchar();
while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
if(c == '-')x = -x;
}

const int INF = 0x7fffffff;
const int MAXN = 10000 + 10;

int dp[MAXN][2], sum[MAXN], num[MAXN], n;

int main()
{
read(n);
for(register int i = 1;i <= n;++ i)
read(num[i]);
for(register int i = 2;i <= n;++ i)
sum[i] = sum[i - 1] + abs(num[i] - num[i - 1]);
for(register int i = n - 1;i >= 1;-- i)
{
if(i == n - 1)
dp[i][0] = abs(num[i + 1] - num[i]);
else
dp[i][0] = min(dp[i + 1][0] + abs(num[i] - num[i + 1]),
dp[i + 1][1] + abs(num[i] - num[i + 2]));
dp[i][1] = INF;
for(register int j = i + 1;j < n - 1;++ j)
{
dp[i][1] = min(dp[i][1],
abs(num[i] - num[j]) + sum[j] - sum[i + 1] +
min(dp[j + 1][0] + abs(num[i] - num[j + 1]),
dp[j + 1][1] + abs(num[i] - num[j + 2])));
}
if(i <= n - 2)
dp[i][1] = min(dp[i][1],
sum[n - 1] - sum[i + 1] + abs(num[i] - num[n - 1]) + abs(num[i] - num
));
dp[i][1] = min(dp[i][1],
sum
- sum[i + 1] + abs(num
- num[i]));
}
printf("%d", min(dp[1][0], dp[1][1]));
return 0;
}


T3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: