zoukankan      html  css  js  c++  java
  • Codeforces 1197 E (dp+sort+二分) (Rust)

    原题链接

    2300分

    大意

    俄罗斯套娃,每个有内容半径in和外围半径out

    in_i<out_i

    如果 in_i >= out_j ,那么j可以放在i内

    定义残留空间 = 一列嵌套的套娃 未使用的半径和 ,如 {1,2},{2,5},{7,9},未使用的白净和为(1-0)+(2-2)+(7-5) = 3

    有效残留空间,如果 一列嵌套的套娃,还能从给出的套娃中选择一个加入这一列,那么原本的残留空间为无效值。如给{1,2},{2,3},{2,5},{7,9},只选择{1,2},{7,9}是无效的嵌套列,而选择{1,2},{2,3},{7,9}是有效的

    令M = 最小的有效残留空间

    求有效残留空间=M的方案数 % MOD

    数据范围

    套娃个数<= 200'000

    半径<=1'000'000'000

    MOD = 1'000'000'007

    题解 翻译自官方题解

    赛内我写了大概十多分钟没写出来,算法是想到n方的 但是没想到怎么优化到时间复杂度内

    https://codeforces.com/blog/entry/68615

    首先我们 把它们按照内半径排序in_i,

    dp[i] = {x,y} 从末尾到第i个,最小的有效残留空间x, 这样的情况下的方案数 y

    dp[i] = {in_i,1} 如果没有 能套在i外面的

    如果有能套在i外面的j 那么

    dp[i].x = min(d[j].x - (out_i-in_i)) = min(d[j].x) - (out_i-in_i)

    我自己考虑漏的一点,假设 我们在尝试i了,那么min[d[ all j such in_j>=out_i ].x] 对于>=i 来说,一定是有效的,当时考虑漏了,在想怎么维护左右游标,来计算有效范围内的最小值

    反证法

    因为我们 要把i放在j内,如果不是有效的,

    首先我们的dp定义保证了 不会插入其它在j以后

    那么意味着,在i和j之间还能插入其它,假设为k

    那么有d[k].x < d[j].x 和我们刚刚假设的min矛盾

    综上

    读入O(n)

    排序O(n log n)

    维护一个minx数组

    每次计算dp[i] 二分>=out_i的坐标,计算完后更新minx 每次O(log n)

    总共O(n log n)

    代码 (Rust)

    https://codeforces.com/contest/1197/submission/57928269

    #![allow(unused_imports)]
    use std::cmp::*;
    use std::collections::*;
    use std::ops::Bound::*;
     
    struct Scanner {
       buffer : std::collections::VecDeque<String>
    }
     
    impl Scanner {
     
       fn new() -> Scanner {
          Scanner {
             buffer: std::collections::VecDeque::new()
          }
       }
     
       fn next<T : std::str::FromStr >(&mut self) -> T {
     
          if self.buffer.len() == 0 {
             let mut input = String::new();
             std::io::stdin().read_line(&mut input).ok();
             for word in input.split_whitespace() {
                self.buffer.push_back(word.to_string())
             }
          }
     
          let front = self.buffer.pop_front().unwrap();
          front.parse::<T>().ok().unwrap()
       }
    }
     
    fn main() {
        const MOD:i32 = 1_000_000_007;
        let mut s = Scanner::new();
        let n : usize = s.next();
        let mut arr:Vec<(i32,i32)> = Vec::new();
        for _i in 0..n {
            let out_i: i32 = s.next();
            let in_i: i32 = s.next();
            arr.push((in_i,out_i));
        }
        arr.sort();
        let mut minx:BTreeMap<i32,(i32,i32)> = BTreeMap::new(); // (in>=, (mincost,cnt))
        let mut ans:i32 = 0;
        for i in arr.iter().rev() {
            let out_i = i.1;
            let in_i = i.0;
     
            // 二分找到 >= out_i 的minx
            //
            let bin_res:(i32,i32) = match minx.range((Included(&out_i), Unbounded)).next() {
                Some(val) => *(val.1),
                None => (out_i,1)
            };
     
            let cost = (bin_res.0 - (out_i - in_i), bin_res.1);
            // 获取当前>=in_i 的 minx 如果没有则是 0
     
            let cur = match minx.range((Included(&in_i), Unbounded)).next() {
                Some(val) => *(val.1),
                None => (cost.0,0)
            };
     
            let count = minx.entry(in_i).or_insert(cur);
            if count.0 > cost.0 {
                ans = cost.1;
                (*count) = cost;
            } else if count.0 == cost.0 {
                (*count).1 += cost.1;
                (*count).1 %= MOD;
                ans = (*count).1;
            }
            // println!("{:?} {:?}", i , count);
        }
        println!("{}",ans );
    }
    

    总结

    最近在看Rust,想说 这lower_bound 用range来写,写得我自闭,但是回过头来看

    感觉用match比c++写 成lower_bound 再判断是否等于.end()更加清晰

    再比如 下面

    entry+or_insert这里

    最开始我的两个if里分别时minx.insert和count操作,这样 连编译都通不过,因为一个变量不允许同时 两个mutable

    此外 赞美一下 .0,.1相对于 c++中的 .first,.second或者说 get<0>(...),get<1>(...)

    简洁而不失去意义

  • 相关阅读:
    按ECS退出全屏模式
    【转】vux (scroller)上拉刷新、下拉加载更多
    vux组件样式大合集
    【转】vue+axios 前端实现登录拦截(路由拦截、http拦截)
    可拖动元素拖动到另外一个元素位置的时候,互相交换位置
    优秀文章链接
    获取kendoDatePicker里的正确日期格式
    给kendo ui 里的控件绑定事件的方法
    有人物联网调试过程
    开源cms系统siteServer的使用记录
  • 原文地址:https://www.cnblogs.com/CroMarmot/p/11264443.html
Copyright © 2011-2022 走看看