Codeforces Round #610 (Div. 2)

A - Temporarily unavailable

题意:给一个x轴,从x=a走到x=b,求其中断网的时间的,断网当且仅当你离路由器x=c距离超过r。

题解:找c2<c1的bug找了半天。

void test_case() {
    ll a, b, c, r;
    scanf("%lld%lld%lld%lld", &a, &b, &c, &r);
    if(a > b)
        swap(a, b);
    ll t = (b - a);
    ll c1 = c - r, c2 = c + r;
    c1 = max(a, c1);
    c2 = min(b, c2);
    ll tt = max(0ll, c2 - c1);
    printf("%lld\n", t - tt);
}

B1 - K for the Price of One (Easy Version)

见下

B2 - K for the Price of One (Hard Version)

题意:去商店买东西,商店有n个物品,每个物品有自己的价格,商店有个优惠活动,当你买恰好k个东西时可以只为其中最贵的那个付款,求有限的钱中买到的最多的物品数量,你可以多次使用优惠。

题解:不管什么东西先排序,当时想到一个贪心:买了一个物品之后假如这个物品的序号>=k,那么它之前的k-1个物品一定就是被它免费的。剩下的用最前面的零头来凑。但是忽略了一个事实,就是买的东西实际上都是从序号1开始的连续的一段,中间是不会断开的。因为可以将用优惠买的物品的点水平左移,知道恰好把零头的后一个给免费了,这样数量不变,花的钱更少。

int n, p, k;
int a[200005];
ll sum[200005];
ll dp[200005];
 
void test_case() {
    scanf("%d%d%d", &n, &p, &k);
    for(int i = 1; i <= n; ++i) 
        scanf("%d", &a[i]);
    sort(a + 1, a + 1 + n);
    for(int i = 1; i <= n; ++i)
        sum[i] = sum[i - 1] + a[i];
    for(int i = 1; i < k; ++i)
        dp[i] = 0;
    for(int i = k; i <= n; ++i)
        dp[i] = dp[i - k] + a[i];
    int ans = 0;
    for(int i = 1; i < k; ++i) {
        if(sum[i] <= p)
            ans = i;
    }
    for(int i = k; i <= n; ++i) {
        int rp = p - dp[i];
        if(rp < 0)
            break;
        int cnt = 0;
        if(i % k)
            cnt = upper_bound(sum + 1, sum + 1 + (i % k), rp) - sum - 1;
        ans = max(ans, cnt + i / k * k);
    }
    printf("%d\n", ans);
}
int n, p, k;
int a[200005];
ll dp[200005];

void test_case() {
    scanf("%d%d%d", &n, &p, &k);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    sort(a + 1, a + 1 + n);
    for(int i = 1; i < k; ++i)
        dp[i] = dp[i - 1] + a[i];
    for(int i = k; i <= n; ++i)
        dp[i] = dp[i - k] + a[i];
    int ans = 0;
    for(int i = 1; i <= n; ++i) {
        if(dp[i] <= p)
            ans = i;
    }
    printf("%d\n", ans);
}

观察了一下题目貌似还可以这么写:

int n, p, k;
int a[200005];

void test_case() {
    scanf("%d%d%d", &n, &p, &k);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    sort(a + 1, a + 1 + n);
    for(int i = 1; i < k; ++i)
        a[i] += a[i - 1];
    for(int i = k; i <= n; ++i)
        a[i] += a[i - k];
    while(a[n] > p)
        --n;
    printf("%d\n", n);
}

C - Petya and Exam

写完这道题居然能加分,而且出得这么快估计是1800的难度想不到官方也这么觉得。

题意:参加一门课的考试,考试的规则非常的奇怪,和正常中国人见过的都不同。

首先考试只有两种题,一种是简单题,每道题耗时固定为a;另一种是困难题,每道题耗时固定为b,保证b>a。分值都是1。

考试的规则并不只是写多少题得多少分,鼓励提前交卷。假如你没有提前交卷,那么有一部分的题目会列为“必需”,当“必需”的题目没有全部被完成的话,这门课就算0分;否则得到与题数相同的分数,包括“必需”和“非必需”的。

题解:很显然又直接按时间排升序,然后贪心,要在某个题变成必需的前夕进行判断。首先先得把“必需”的时间全部花出去(小心溢出和运算符优先级),剩下的尽可能填“非必需”的简单题,然后尽可能填“非必需”的困难题。这样写会漏一种情况,因为在最后一个变成“必需”之后没有下一个变成“必需”的前夕了,而是考试结束。所以先特判掉全部变成“必需”的情况是不是可以待到考试结束全部做完,然后再贪心。

现在觉得好像把时间离散化的话就不需要使用nxt这种丑陋的写法了。

int n, T, a, b;
struct Problem {
    int t, d;
    bool operator<(const Problem& p)const {
        return t < p.t;
    }
} p[200005];

void test_case() {
    scanf("%d%d%d%d", &n, &T, &a, &b);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &p[i].d);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &p[i].t);
    int suma = 0, sumb = 0;
    for(int i = 1; i <= n; ++i) {
        if(p[i].d == 0)
            ++suma;
        else
            ++sumb;
    }
    if(1ll * suma * a + 1ll * sumb * b <= T) {
        printf("%d\n", n);
        return;
    }
    sort(p + 1, p + 1 + n);
    int ans = 0, cura = 0, curb = 0;
    for(int i = 1; i <= n;) {
        int curt = p[i].t - 1;
        if(curt >= (1ll * cura * a + 1ll * curb * b)) {
            int rest = curt - (1ll * cura * a + 1ll * curb * b);
            int cnta = min(suma, rest / a);
            //这里并不可能溢出
            rest -= cnta * a;
            int cntb = min(sumb, rest / b);
            //这里并不可能溢出
            rest -= cntb * b;
            ans = max(ans, cura + curb + cnta + cntb);
        }
        int nxt = i;
        while(nxt <= n && p[nxt].t == p[i].t) {
            if(p[nxt].d == 0) {
                ++cura;
                --suma;
            } else {
                ++curb;
                --sumb;
            }
            ++nxt;
        }
        i = nxt;
    }
    printf("%d\n", ans);
}

发现上面的写法里面有两个惊人的乘法没有变 long long 的,有点害怕。以后假如不卡时间可以直接上 long long 就不会出任何事。

猜你喜欢

转载自www.cnblogs.com/KisekiPurin2019/p/12096103.html
今日推荐