[AGC072A] Rhythm Game
Genius_Star · · 题解
或许更好的阅读体验。
思路:
牛逼题,拜谢 jds 场上秒了这题。
因为每次按了都要回来,所以对于一个按钮是可以单独考虑的,考虑收集这个按钮出发时间的限制,显然必须在
于是可以看作在
可以看作有若干个任务,第
看起来很难做啊,能不能找一些性质,如果
现在加上
假设空闲时间内去做了任务
那么根据前面的贪心策略,空闲时间内如果先做了
上面那个过程显然可以用 dp 刻画,定义
然后考虑怎么算中间的是否能全部完成,显然做完
时间复杂度为
完整代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define lowbit(x) x & (-x)
using namespace std;
typedef long long ll;
const int N = 5050;
const ll inf = 1e18;
inline ll read(){
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')
f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
inline void write(ll x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
struct Node{
ll l, r, tim;
inline bool operator<(const Node&rhs)const{
if(r ^ rhs.r)
return r < rhs.r;
if(l ^ rhs.l)
return l < rhs.l;
return tim < rhs.tim;
}
}a[N];
int T, n;
ll x, t, d;
ll s[N], dp[N];
inline void solve(){
n = read(), d = read();
for(int i = 1; i <= n; ++i){
t = read(), x = read();
a[i] = {t - x, t + d + x, x * 2ll};
a[i].l = max(a[i].l, 0ll);
}
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; ++i)
s[i] = s[i - 1] + a[i].tim;
for(int j = 1; j <= n; ++j){
// cerr << a[j].l << ' ' << a[j].r << ' ' << a[j].tim << '\n';
ll mn = inf;
dp[j] = inf;
for(int i = j - 1; i >= 0; --i){
if(dp[i] == inf){
if(i != j - 1)
mn = min(mn, a[i + 1].r - s[i + 1]);
continue;
}
ll t = max(a[j].l, dp[i]) + a[j].tim;
if(t > a[j].r){
if(i != j - 1)
mn = min(mn, a[i + 1].r - s[i + 1]);
continue;
}
if(i != j - 1)
mn = min(mn, a[i + 1].r - s[i + 1]);
if(t - s[i] <= mn){
// cerr << j << ' ' << i << ' ' << t << ' ' << mn << '\n';
dp[j] = min(dp[j], t + s[j - 1] - s[i]);
}
// cerr << a[i + 1].r - s[i + 1] << '\n';
}
// cerr << dp[j] << '\n';
}
if(dp[n] == inf)
puts("No");
else
puts("Yes");
}
int main(){
T = read();
while(T--)
solve();
return 0;
}