zoukankan      html  css  js  c++  java
  • Atcoder Grand Contest 023D

    Atcoder Grand Contest 023D - Go Home

    题目大意

    • 一条路上有 N N N幢房子,每幢房子住有 X i X_i Xi个人,最初汽车从某个地点 S S S出发,装着所有的人,汽车每次走一个单位,向左或向右由所有人投票决定,少数服从多数,如果汽车到达了自己所住的房子则下车。
    • 每个人都会尽可能使自己尽早到达,求最晚到达的人的到达时间。
    • N ≤ 1 0 5 N≤10^5 N105

    题解

    • 第一眼以为维护前缀和后缀和,每次最最贪心地判断左右哪边人多久往哪边走,但一看样例就会发现这样是错的,
    • 也就是说,对于每个人而言,不一定每次都向着自己想去的地方投票就一定能更早到达。
    • 举个例子,加入当前左边依次有两幢房子,人数为 A , B A,B A,B,右边一幢房子人数为 C C C
    • 满足 A < C A<C A<C B < C B<C B<C A + B > C A+B>C A+B>C
    • 考虑 A A A中的人会如何投票?
    • 如果 A A A向左投, B B B也向左投, C C C会向右投,那么汽车会向左移动,可是并不能一直移动到 A A A
    • 直到 B B B的人下车后,向左的人数就小于向右的人数了,那么汽车右会一直移动到最右边再回来到 A A A
    • 因此 A A A中的人会先投右边, 让 C C C先到,他们自己便也可以更早到达。
    • 这是为什么呢?考虑更一般的情况:
    • 若当前最左边的人数为 A A A,最右边的人数为 B B B,满足 A < B A<B A<B,中间大小不考虑( A > B A>B A>B同理),
    • 如果汽车一直向左走,虽然会不断靠近 A A A,但总会有一个时刻,向左的人数小于向右的人数了,而使汽车向右走去,绕到最右端才回来,
    • 这样看的话,若 A < B A<B A<B,则 A A A一定会比 B B B更晚到,且 B B B到达之后,再到达 A A A之间所用的时间是确定的,即为二者之间的距离,那么 A A A为了自己先到,会尽可能让 B B B先到,所以 A A A会向右投票,
    • 于是,可以忽略 A A A的存在,直接给 B B B加上 A A A,然后总时间加上二者之间的距离,于是剩下的部分转为原问题的一个子问题,按同样的思路继续求解,只需要记录当前子问题的区间 [ l , r ] [l,r] [l,r],可以用递归实现,复杂度 O ( n ) O(n) O(n)
    • 在这个过程中,相当于推出汽车运动的反向过程,给 B B B加上 A A A相当于汽车有一个 B B B A A A的移动过程。
    • 那边界条件是什么?
    • 根据题意,如果子问题的整个区间在 S S S的左侧或右侧了,那么所有人的意见就会统一进行,按顺序直接走完。
    • 要注意,如果当前子问题中汽车的移动反向和上一次相同的话,那么不用计入答案,因为这一次的答案会被上一次包含。

    代码

    #include<cstdio> 
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 100010
    ll ans = 0;
    int t;
    struct {
    	int x; ll s;
    }a[N];
    void ct(int l, int r, int o) {
    	if(a[l].x >= t) {
    		ans += a[r].x - t;
    		return;
    	}
    	if(a[r].x <= t) {
    		ans += t - a[l].x;
    		return;
    	}
    	if(a[l].s >= a[r].s) {
    		a[l].s += a[r].s;
    		if(o != 0) ans += a[r].x - a[l].x;
    		ct(l, r - 1, 0);
    	}
    	else {
    		a[r].s += a[l].s;
    		if(o != 1) ans += a[r].x - a[l].x;
    		ct(l + 1, r, 1);
    	}
    }
    int main() {
    	int n, i;
    	scanf("%d%d", &n, &t);
    	for(i = 1; i <= n; i++) scanf("%d%lld", &a[i].x, &a[i].s);
    	ct(1, n, -1);
    	printf("%lld", ans);
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    Connection parameters are correct , SSL not enabled
    log4j配置文件的详解
    java.lang.IllegalArgumentException: addChild: Child name '/SSHE' is not unique
    MYSQL的三种注释
    Oracle19c 单节点ASM 存储模式数据库实例搭建过程
    [专题]中立遭质疑,提价遭反对,ARM的生存难题怎么破?
    快速排序的理解
    chrome审查元素功能,web开发强大帮手
    MyEclipse Server view报错解决方法
    把Java程序打包成jar文件包并执行
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910024.html
Copyright © 2011-2022 走看看