Gym - 101611H Hilarious Cooking——模拟

版权声明:欢迎大家转载,转载请注明出处 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;
}

猜你喜欢

转载自blog.csdn.net/hao_zong_yin/article/details/82784815
今日推荐