版权声明:欢迎大家转载,转载请注明出处 https://blog.csdn.net/hao_zong_yin/article/details/82784815
求每段的最大值最小值,加起来判断T是否在这个范围内就好了
每一段最大值分升降和升平一个降两种情况,但转折点的横坐标都可以表示为t=(y2-y1+x2+x1)/2下取整,之后判一下t和t+1对应的纵坐标是否相等就可以判断这两种情况了
每一段最小值同理,注意转折点的值不能为0,和0取个max就行了
然后单独求一下头尾就做完了
区间都采用左闭右开比较好写,注意数值全部用long long
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
ll cal(ll x, ll y) { ll n = y-x+1; return n*(x+y)/2; }
ll calmax(ll x1, ll y1, ll x2, ll y2) {
if (x2-x1 < abs(y2-y1)) return -1;
ll t = (y2-y1+x2+x1)/2, v = y1+t-x1;
if (y1+t-x1 == y2+x2-t) return cal(y1, v) + cal(y2, v) - v;
else return cal(y1, v) + cal(y2, v);
}
ll calmin(ll x1, ll y1, ll x2, ll y2) {
if (x2-x1 < abs(y2-y1)) return -1;
ll t = (y1-y2+x1+x2)/2, v = y1-(t-x1);
if (y1-(t-x1) == y2-(x2-t)) {
if (v < 0) return cal(0, y1) + cal(0, y2);
else return cal(v, y1) + cal(v, y2) - v;
}
else {
if (v < 0) return cal(0, y1) + cal(0, y2);
else return cal(v, y1) + cal(v, y2);
}
}
ll T, n, m, x[maxn], y[maxn];
int main() {
scanf("%lld%lld%lld", &T, &n, &m);
for (int i = 1; i <= m; i++) scanf("%lld%lld", &x[i], &y[i]);
ll minv = 0, maxv = 0;
minv += cal(max(0LL, y[1]-(x[1]-1)), y[1])-y[1];
maxv += cal(y[1], y[1]+(x[1]-1))-y[1];
bool ok = true;
for (int i = 1; i < m; i++) {
ll t1 = calmin(x[i], y[i], x[i+1], y[i+1]), t2 = calmax(x[i], y[i], x[i+1], y[i+1]);
if (t1 == -1 || t2 == -1) { ok = false; break; }
minv += t1-y[i+1];
maxv += t2-y[i+1];
}
minv += cal(max(0LL, y[m]-(n-x[m])), y[m]);
maxv += cal(y[m], y[m]+(n-x[m]));
if (minv <= T && T <= maxv && ok) puts("Yes");
else puts("No");
return 0;
}