zoj 3981 Balloon Robot
https://vjudge.net/problem/ZOJ-3981
题意:
有m个座位,其中n个队伍坐在这些位置上,一个队伍一个座位。当一个队A了题之后,他们们会得到气球,假设他们在a时刻A题,但是在b时刻才得到气球,那么他们的不高兴值就会增加b - a。现在主办方安排了一个机器人发气球,机器人每时刻都会向右移动一个位置(当然是循环的),到了一个位置,如果这个位置上有队伍并且A了题没有得到气球,那么就会把气球发给这个队伍。现在给出每个队伍的位置和A题的情况,要求安排机器人的起始位置使得所有队伍的不开心值之和最小。
思路:
首先可以假设机器人在1位置,计算出每个题的气球需要等待的时间,然后接下来证明一个猜想,枚举的时间点必然是A题的时刻:
假设在当前枚举的时刻t没有A题,那么在枚举到t+1时刻,那么必然所有的A题的等待时间会减少1,直到有A题的时刻之后,时间才会增加。
首先把每个的等待时间排个序(求等待时间的时候,使用了二分法),之后顺序枚举
公式 ans = min(sum + i * m - d[i] * q),因为前面的A题时刻在起点后移之后必定会从m - 1开始递减的,所以有加上i * m,然后全部的等待时间都会减少d[i],所以每一个都减去。
总的时间复杂度为O(n)。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 #include <algorithm> 5 using namespace std; 6 7 int d[100005]; 8 int pos[100005]; 9 10 bool meet(long long k,int tmp,int m,int b) 11 { 12 long long ans = k * m + tmp; 13 14 if (ans >= b) return true; 15 else return false; 16 } 17 18 int main() 19 { 20 int t; 21 22 scanf("%d",&t); 23 24 while (t--) 25 { 26 int n,m,p; 27 28 scanf("%d%d%d",&n,&m,&p); 29 30 long long sum = 0; 31 32 for (int i = 1;i <= n;i++) 33 scanf("%d",&pos[i]); 34 35 for (int i = 0;i < p;i++) 36 { 37 int a,b; 38 39 scanf("%d%d",&a,&b); 40 41 a = pos[a]; 42 43 long long l = 0,r = 1000000000; 44 45 int tmp = a - 1; 46 47 while (l < r - 1) 48 { 49 long long mid = (l + r) >> 1; 50 51 if (meet(mid,tmp,m,b)) r = mid; 52 else l = mid + 1; 53 } 54 55 while (meet(r - 1,tmp,m,b)) r--; 56 57 d[i] = r * m + tmp - b; 58 59 sum += d[i]; 60 61 //printf("%d 233\n",d[i]); 62 } 63 64 sort(d,d+p); 65 66 long long ans = 1000000000000000; 67 68 for (int i = 0;i < p;i++) 69 { 70 long long tmp = sum + (long long)i * m - (long long) p * d[i]; 71 72 ans = min(tmp,ans); 73 } 74 75 printf("%lld\n",ans); 76 } 77 78 return 0; 79 }
康复训练中~欢迎交流!