Zoj3981 Balloon Robot

Zoj3981 Balloon Robot

可以把所有的题目都挪到位置1

mp表示 如果机器人在时间mp.first时移动到位置1的话,有mp.second道题刚好unhappiness为0(刚做完就拿到了气球)

由于最多有p(1e5)道题,可以暴力枚举map(用迭代器it),假设机器人在位置1时间为it.first,那么在对于在时间mp.first做完的题目,会等待的时间为(it.first - mp.first + MOD) % MOD

如果每次it都要用所有的mp来算的话 时间复杂度为p^2,显然会爆

可以发现,it到下一个it(记为nxt_it)后,除了nxt_it.second的其他所有题都会增加unhappiness,每个问题增加的差值为delta = nxt_it.first - it.first,而nxt_it本身的nxt_it.second道题的unhappiness会减为0

这个过程需要脑子清醒的情况下仔细思考

#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
#define int64 long long
template <class T> void next_num(T &num) {
    char c; bool is_minus = false;
    while((c = getchar())) {
        if(c >= '0' && c <= '9') {
            num = c - '0';
            while((c = getchar()) && c >= '0' && c <= '9')
                num = num * 10 + c - '0';
            ungetc(c, stdin);
            if(is_minus) num = -num;
            break;
        }
        else if(c == '-') is_minus = true;
    }
}
#define MAXN 100000
int T, n, m, p;
int s[MAXN + 5], a[MAXN + 5], b[MAXN + 5];
map<int, int> mp;
int main() {
    next_num(T);
    while(T-- > 0) {
        mp.clear();
        next_num(n);
        next_num(m);
        next_num(p);
        for(int i = 1; i <= n; ++i)
            next_num(s[i]);
        for(int i = 1; i <= p; ++i) {
            next_num(a[i]);
            next_num(b[i]);
            if(s[a[i]] == 1) b[i] = b[i] % m;
            else b[i] = (b[i] - s[a[i]] + 1 + m) % m;
            if(!mp.count(b[i]))
                mp[b[i]] = 0;
            ++mp[b[i]];
        }
        int64 sum = 0, min_sum;
        map<int, int>::iterator it, last;
        for(it = mp.begin(); it != mp.end(); ++it)
            sum += 1LL * ((mp.begin()->first - it->first + m) % m) * it->second;
        min_sum = sum;
        for(last = mp.begin(), it = ++mp.begin(); it != mp.end(); ++it, ++last) {
            int delta = it->first - last->first;
            sum += 1LL * delta * (p - it->second);
            sum -= 1LL * it->second * (m - delta);
            if(sum < min_sum)
                min_sum = sum;
        }
        printf("%lld\n", min_sum);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值