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);
}
}