zoj3891 2017CCPC秦皇岛站A

题意

n支队伍,一张桌子有m个座位顺时针编号1~m。p个预言。预言a队伍在b时刻ac一道题目。机器人每个时刻都顺时针走一步,有需要气球的就发。每支队伍,ac后多少时刻没收到气球就有多少不开心的值,问机器人起始位置在哪里可以使得总的不高兴值最小。输出最小的不高兴值。

题解

n 1e5  m 1e9 ,robot的可能出发位置一定是在这1e5个之内,就是当它到某个队伍可以恰好给这个队伍气球的时候,这个位置一定是其中之一。

可以将所有队伍的AC时间等价到一支队伍上,例如第一支队伍位置p1,A题时间为a,第二支队伍位置是p2,A题时间为b,那么其实可以转化为第一支队伍AC另外一道题的时间是 b-(p2-p1),这里注意考虑取模!

假设机器人从第一支队伍的位置出发,当b不为0时,那么每次答案都需要加上(m-b) b为A题的时间。//绕一圈回来 等待时间+(m-b),对于假设从pos[1]出发的ans求解O(n),如果对每个位置都这样求->O(n^2)炸了呜呜呜。

所以对于这n个可能的起始位置,我们可以做到每次O(1)转移得到相应答案 再取min,怎么转移呢?

对于前面求出的每一个b(映射的AC时间)从小到大枚举,->机器人起点变化

ans += p * (现在的位置 - 上一个);//所有点都加上这一段的时间

ans -= m * B;//刚好在这儿的点减掉一个轮回

答案取min,nice~

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<cmath>

using namespace std;
const int MaxN = 1e5 + 5;
typedef long long LL;

int t,a,b,n;
LL m,p;
int pos[MaxN];
LL ans = 0LL;
map<int,int>mp;

int main(){
	scanf("%d",&t);
	while(t--){
		ans = 0LL;
		mp.clear();
		scanf("%d %lld %lld",&n,&m,&p);
		for(int i = 1;i <= n; i++) scanf("%d",&pos[i]);
		for(int i = 1;i <= p; i++){
			scanf("%d %d",&a,&b);
			b = b - ((pos[a] - pos[1]) + m) % m;
			b = (b + m) % m;
			mp[b]++;
			if(b) ans += m - b;
		}
		LL ANS = ans;
		int lst = 0;
		for(auto it = mp.begin();it != mp.end(); it++){
			LL de = it->first - lst;
			if(!de) continue;
			ans += p * de;
			ans -= it->second * m;
			ANS = min(ANS,ans);
			lst = it->first;
		}
		printf("%lld\n",ANS);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值