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>(...)
简洁而不失去意义
Codeforces 1197 E (dp+sort+二分) (Rust)的更多相关文章
- Codeforces 830A. Office Keys (贪心二分 or DP)
原题链接:http://codeforces.com/contest/830/problem/A 题意:在一条数轴上分别有n个人和k把钥匙(n<=k),以及一个目的地,每个人要各自拿到一个钥匙后 ...
- codeforces 487B B. Strip(RMQ+二分+dp)
题目链接: B. Strip time limit per test 1 second memory limit per test 256 megabytes input standard input ...
- Codeforces 865C Gotta Go Fast 二分 + 期望dp (看题解)
第一次看到这种骚东西, 期望还能二分的啊??? 因为存在重置的操作, 所以我们再dp的过程中有环存在. 为了消除环的影响, 我们二分dp[ 0 ][ 0 ]的值, 与通过dp得出的dp[ 0 ][ 0 ...
- Codeforces 749E Gosha is hunting 二分+DP
很神奇的一题 看完题解不由惊叹 题意:$n$个神奇宝贝 $a$个普通球 $b$个高级球 普通球抓住$i$神奇宝贝的概率为$u[i]$ 高级球为$p[i]$ 一起用为$u[i]+p[i]-u[i]*p[ ...
- CodeForces - 847B Preparing for Merge Sort 二分
http://codeforces.com/problemset/problem/847/B 题意:给你n个数(n<2e5)把它们分成若干组升序的子序列,一行输出一组.分的方法相当于不断找最长递 ...
- codeforces 459E E. Pashmak and Graph(dp+sort)
题目链接: E. Pashmak and Graph time limit per test 1 second memory limit per test 256 megabytes input st ...
- codeforces 666A (DP)
题目链接:http://codeforces.com/problemset/problem/666/A 思路:dp[i][0]表示第a[i-1]~a[i]组成的字符串是否可行,dp[i][1]表示第a ...
- CodeForces 377B---Preparing for the Contest(二分+贪心)
C - Preparing for the Contest Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d ...
- Codeforces 484B Maximum Value(高效+二分)
题目链接:Codeforces 484B Maximum Value 题目大意:给定一个序列,找到连个数ai和aj,ai%aj尽量大,而且ai≥aj 解题思路:类似于素数筛选法的方式,每次枚举aj,然 ...
随机推荐
- 《剑指offer》面试题14 调整数组顺序使奇数位于偶数前面 Java版
(输入整数数组,使所有奇数位于前半部分,所有偶数位于后半部分.) 我的方法:想到用两个下标分别表示奇数和偶数的界线,一个在开头,一个在末尾,判断每一个数字的类别,然后将它放入对应的范围内,移动下标,直 ...
- dfs(枚举)
http://codeforces.com/gym/100989/problem/L L. Plus or Minus (A) time limit per test 1.0 s memory lim ...
- Vue基于vuex、axios拦截器实现loading效果及axios的安装配置
准备 利用vue-cli脚手架创建项目 进入项目安装vuex.axios(npm install vuex,npm install axios) axios配置 项目中安装axios模块(npm in ...
- 计算机体系结构——流水线技术(Pipelining)
本文导读: 一.并行技术 .并行技术分类 .新技术的设计与实现 .指令周期 二.流水线技术 .什么是流水线 .指令重叠方式 .流水工作设计 .流水线的描述方法(时空图) .流水线特点 三.流水线的分类 ...
- BUUCTF--findit
测试文件:https://buuoj.cn/files/7b8602971727c6c82ec0d360d5cad2c0/6a428ff2-25d7-403c-b28e-3f980a10a5a2.ap ...
- mysql的sql语句优化方法面试题总结
mysql的sql语句优化方法面试题总结 不要写一些没有意义的查询,如需要生成一个空表结构: select col1,col2 into #t from t where 1=0 这类代码不会返回任何结 ...
- mysql中,表与表之间的关系
""" 1.字段的修改.添加.删除 2.多表关系(外键) 3.单表详细操作:增删改,查(各种条件) """ 字段操作 create ta ...
- centos误删除文件如何恢复
当意识到误删除文件后,切忌千万不要再频繁写入了,否则你的数据恢复的数量将会很少. 而我们要做的是,第一时间把服务器上的服务全部停掉,直接killall 进程名 或者 kill -9 pid . 然后把 ...
- DDD领域驱动设计初探(一):聚合
前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...
- 英国已有500万宽带用户接入并开始使用IPv6技术
2018年英国首家为客户提供IPv6的主要ISP.随着所有现有的符合条件的用户线路启用,约90%的固定宽带用户群接入并开始使用IPv6,为IPv6互联网增加了超过500万个新眼球. 英国IPv6项目于 ...