   # Codeforces Round #687 (Div. 1, based on Technocup 2021 Elimination Round 2) D - Cakes for Clones DP

## D. Cakes for Clones

You live on a number line. You are initially (at time moment 𝑡=0) located at point 𝑥=0. There are 𝑛 events of the following type: at time 𝑡𝑖 a small cake appears at coordinate 𝑥𝑖. To collect this cake, you have to be at this coordinate at this point, otherwise the cake spoils immediately. No two cakes appear at the same time and no two cakes appear at the same coordinate.

You can move with the speed of 1 length unit per one time unit. Also, at any moment you can create a clone of yourself at the same point where you are located. The clone can't move, but it will collect the cakes appearing at this position for you. The clone disappears when you create another clone. If the new clone is created at time moment 𝑡, the old clone can collect the cakes that appear before or at the time moment 𝑡, and the new clone can collect the cakes that appear at or after time moment 𝑡.

Can you collect all the cakes (by yourself or with the help of clones)?

## Input

The first line contains a single integer 𝑛 (1≤𝑛≤5000) — the number of cakes.

Each of the next 𝑛 lines contains two integers 𝑡𝑖 and 𝑥𝑖 (1≤𝑡𝑖≤109, −109≤𝑥𝑖≤109) — the time and coordinate of a cake's appearance.

All times are distinct and are given in increasing order, all the coordinates are distinct.

## Output

Print "YES" if you can collect all cakes, otherwise print "NO".

input

3

2 2

5 5

6 1

output

YES

input

3

1 0

5 5

6 2

output

YES

input

3

2 1

5 5

6 0

output

NO

## Note

In the first example you should start moving towards 5 right away, leaving a clone at position 1 at time moment 1, and collecting the cake at position 2 at time moment 2. At time moment 5 you are at the position 5 and collect a cake there, your clone collects the last cake at time moment 6.

In the second example you have to leave a clone at position 0 and start moving towards position 5. At time moment 1 the clone collects a cake. At time moment 2 you should create a new clone at the current position 2, it will collect the last cake in future. You will collect the second cake at position 5.

In the third example there is no way to collect all cakes.

## 题解

3方的dp

for (int i=1;i<=n;i++) {
for (int j=i+1;j<=n;j++) {
for (int k=i-1;k<=n;k++) {
if (j!=k) {
dp[i][j]=min(dp[i][j], cost + dp[i-1][k]);
}
}
// 转移一下 j==k 的情况，就可以到处放克隆体
}
}


n3肯定是会TLE的，优化一下发现有些状态是不需要的，我们不需要存储克隆体在j的最小花费。

dp[i][j]表示吃完了[1,i]的所有蛋糕，人在x[i]，分身放在x[j]是否可行。

## 代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5005;
int n;
long long t[maxn],x[maxn];
long long dp[maxn][maxn],minTime[maxn];
long long dis(long long x,long long y) {
return abs(x-y);
}
int main() {
cin>>n;
for (int i=1;i<=n;i++) {
cin>>t[i]>>x[i];
minTime[i] = 1e17;
}
minTime=0;
dp=1;
for (int i=1;i<=n;i++) {
if (x[i] == 0) {
dp[i]=1;
}
}

for (int i=1;i<=n;i++) {
// 从x[i-1]点出发, 不靠分身
if (minTime[i-1] <= t[i-1]) {
minTime[i] = min(minTime[i], max(minTime[i-1] + dis(x[i], x[i-1]), t[i-1]));
if (minTime[i] <= t[i]) {
dp[i][i]=1;
}
}

// 站在i点，分身放在j点，又回来
for (int j=i;j<=n;j++) {
if (minTime[i]+2*dis(x[i],x[j])<=t[i]) { // 过去又回来
dp[i][j]=1;
}
}

// 从i-1点出发，人在i，分身仍然留在j
for (int j=i+1;j<=n;j++) {
if (dp[i-1][j] && t[i-1] + dis(x[i], x[i-1]) <= t[i]) {
dp[i][j] = 1;
}
}

// 从i-1 -> j放下分身，i-1 -> i吃
for (int j=i+1;j<=n;j++) {
if (minTime[i-1]<=t[i-1] && max(t[i-1],minTime[i-1]+dis(x[j],x[i-1]))+dis(x[j],x[i])<=t[i]) {
dp[i][j]=1;
}
}

// 2 dp[i-1][i]是合法的 -> dp[i+1][i] / minTime[i+1]
if (dp[i-1][i] && i+1 <= n) {
minTime[i+1] = min(minTime[i+1], max(t[i-1] + dis(x[i+1],x[i-1]), t[i]));
if (minTime[i+1] <= t[i+1]) {
dp[i+1][i+1]=1;
}
// 先去j，等待分身i吃完，放下分身，再去i+1
for (int j=i+1;j<=n;j++) {
if (max(t[i-1]+dis(x[j],x[i-1]),t[i])+dis(x[j],x[i+1]) <= t[i+1]) {
dp[i+1][j] = 1;
}
}
}
}
if (dp[n][n] == 1 || dp[n-1][n] == 1) {
cout<<"YES"<<endl;
} else {
cout<<"NO"<<endl;
}
}
posted @ 2020-12-14 21:07  qscqesze  阅读(150)  评论(0编辑  收藏  举报