Codeforces 1290D - Coffee Varieties(分块暴力+完全图的链覆盖)
Easy version:Codeforces 题面传送门 & 洛谷题面传送门
Hard version:Codeforces 题面传送门 & 洛谷题面传送门
发现自己交互题烂得跟 sh*t 一样……于是不管三七二十一先来两道再说(
首先考虑最 trivial 的情况,也就是 \(k=1\) 和 \(k=n\) 两种情况,对于 \(k=1\) 你就 \(\mathcal O(n^2)\) 地检查一遍所有的 pair,具体来说我们枚举所有 \(i,j(i<j)\),然后依次询问 \(i,j\),如果询问到 \(j\) 时发现队列中存在 \(i\),就说明在 \(j\) 前面有存在与 \(a_j\) 相同的值,此时 \(j\) 不会对答案产生贡献,因此我们考虑开一个数组 \(is_i\) 表示 \(i\) 是否对答案产生贡献,每访问到这样的 \(j\) 就将 \(is_j\) 设为 \(0\) 即可。最后统计 \(\sum\limits_{i=1}^nis_i\) 即可,总询问次数 \(\dbinom{n}{2}·2=n(n-1)\)
\(k=n\) 的情况更容易,直接扫一遍,如果插入一个 \(i\) 时发现 \(i\) 已经存在,就将 \(is_i\) 设为 \(0\) 即可,总查询次数 \(n\)。
现在继续思考更一般的情形,也就是 \(k\ne 1\) 且 \(k\ne n\) 的情形,我们考虑将两个暴力结合一下,也就是人们常说的分块暴力,我们考虑将每 \(\dfrac{k}{2}\) 个元素形成一块,询问时对每两个块 \(i,j(i<j)\) 跑一遍上面 \(k=n\) 的暴力然后清空队列,这样对于每一对满足 \(x<y\) 且 \(a_x=a_y\) 的 \((x,y)\),如果 \(x,y\) 在同一块中那只要扫到 \(x\) 所在的块就会统计到这个二元组,否则在遍历 \(x\) 所在的块与 \(y\) 所在的块时会遍历到该二元组,这也就证明了上述算法的正确性。
算下询问次数,总共 \(\dfrac{2n}{k}\) 个块,遍历次数 \(\dbinom{2n/k}{2}=\mathcal O(\dfrac{2n^2}{k^2})\),而每次遍历要检验 \(k\) 个元素,因此总操作次数 \(\dfrac{2n^2}{k}\),可以通过 easy version。
const int MAXN=1<<10;
int n,k,is[MAXN+5];
bool query(int x){
printf("? %d\n",x);fflush(stdout);
char c;cin>>c;return (c=='Y');
}
int main(){
scanf("%d%d",&n,&k);int siz=max(k>>1,1);
for(int i=1;i<=n;i++) is[i]=1;int cnt=n/siz;
for(int i=1;i<=cnt;i++) for(int j=i+1;j<=cnt;j++){
for(int l=(i-1)*siz+1;l<=i*siz;l++) is[l]&=!query(l);
for(int l=(j-1)*siz+1;l<=j*siz;l++) is[l]&=!query(l);
printf("R\n");fflush(stdout);
} int sum=0;for(int i=1;i<=n;i++) sum+=is[i];
printf("! %d\n",sum);fflush(stdout);
return 0;
}
接下来考虑 hard version,不难发现上述算法的瓶颈在于,每次遍历两块时都要重新清空队列,效率太低。考虑优化。我们考虑将所有待检验的二元组 \((i,j)\) 看作一个边,那么显然会连成一个 \(\dfrac{2n}{k}\) 个点的完全图(注:这里可能有人会有疑问,在之前的算法中我们不是强制钦定 \(i\) 必须小于 \(j\) 吗?那这里不应该也有 \(i<j\) 吗?为什么会得到一张完全图呢?事实上我们并不一定非得要 \(i<j\),如果我们采取这样一个思想:维护一个集合表示目前没有值与其重复的元素,对于某个 \(a_i\),如果我们发现在该集合中存在某个元素,满足值与其相同,就将 \(a_i\) 从集合中删除,如此进行下去直到集合中无法再删除元素。此时 \(is_i\) 的定义要变为 \(a_i\) 是否还在集合中。不难发现这两个思路是等价的,而后者并不需要用到 \(i<j\) 这个性质),我们的目标即是覆盖这些边。不难发现对于完全图中的一条长度为 \(l\) 的链 \(a_1\to a_2\to a_3\to\cdots\to a_l\),覆盖它们所需的最小代价为 \(l·\dfrac{k}{2}\),具体步骤就是对于这条链上所有点一一询问即可。而显然我们不会重复覆盖相同的边,因此对于某个链覆盖的方案,覆盖整张图所需的最少代价就是 \(\dfrac{k}{2}·(\dbinom{2n/k}{2}+\text{使用链的个数})\)。而对于一个 \(n\) 个点(\(n\) 是偶数)的完全图而言有一个性质,就是覆盖它的边集所用的最少的链的个数是 \(\dfrac{n}{2}\),具体构造是我们枚举所有 \(s\in[1,\dfrac{n}{2}]\),然后 \(s\to s+1\to s-1\to s+2\to s-2\) 这样之字形反复横跳,如果超过 \(n\) 就回到 \(1\),如果小于 \(1\) 就回到 \(n\)。可以证明这样操作之后必然可以覆盖所有边,大概证明方式就是,对于每一条边 \((i,j)\),显然恰好存在两个点 \(s\) 满足从 \(s\) 开始能够遍历到这个边,而这两个 \(s\) 刚好差 \(\dfrac{n}{2}\),因此必定恰好有一个 \(s\) 在 \([1,\dfrac{n}{2}]\) 中。具体细节留给读者自己思考。操作次数 \(\dfrac{k}{2}·(\dbinom{2n/k}{2}+\dfrac{2n}{2k})=\dfrac{k}{2}·(\dfrac{n}{k}·(\dfrac{2n}{k}-1)+\dfrac{n}{k})=\dfrac{n^2}{k}\),可以通过 hard version。
const int MAXN=1<<10;
int n,k,siz,cnt,is[MAXN+5];
bool query(int x){
printf("? %d\n",x);fflush(stdout);
char c;cin>>c;return (c=='Y');
}
void deal(int x){
for(int i=(x-1)*siz+1;i<=x*siz;i++) if(is[i]&&query(i)) is[i]=0;
}
int main(){
scanf("%d%d",&n,&k);siz=max(k>>1,1);cnt=n/siz;
for(int i=1;i<=n;i++) is[i]=1;
for(int i=1;i<=n/k;i++){
int cur=0;
for(int j=1;j<=cnt;j++) deal((i+cur+cnt)%cnt+1),cur=(cur<=0)-cur;
printf("R\n");fflush(stdout);
} int sum=0;for(int i=1;i<=n;i++) sum+=is[i];
printf("! %d\n",sum);fflush(stdout);
return 0;
}
Codeforces 1290D - Coffee Varieties(分块暴力+完全图的链覆盖)的更多相关文章
- Codeforces Beta Round #13 E. Holes 分块暴力
E. Holes Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/13/problem/E Des ...
- Codeforces#86D Powerful array(分块暴力)
Description An array of positive integers a1, a2, ..., an is given. Let us consider its arbitrary su ...
- Codeforces Round #616 Coffee Varieties
题意 不太容易讲清,看英文吧 codeforces 做法 先从简单的看起 将块以\(\frac{k}{2}\)个元素为界,然后类似线段树一样递归下去,每次一层的左子树跟右子树的块相互暴力比较 \[\b ...
- (分块暴力)Time to Raid Cowavans CodeForces - 103D
题意 给你一段长度为n(1 ≤ n ≤ 3·1e5)的序列,m (1 ≤ p ≤ 3·1e5)个询问,每次询问a,a+b,a+2b+...<=n的和 思路 一开始一直想也想不到怎么分,去维护哪些 ...
- D. Alyona and a tree 公式转换 + 分块暴力
http://codeforces.com/problemset/problem/740/D 对于每一对<u, v>.设dis[u]表示root到点u的距离,那么dis<u去v> ...
- Codeforces 1129D - Isolation(分块优化 dp)
Codeforces 题目传送门 & 洛谷题目传送门 又独立切了道 *2900( 首先考虑 \(dp\),\(dp_i\) 表示以 \(i\) 为结尾的划分的方式,那么显然有转移 \(dp_i ...
- Codeforces Gym 100015H Hidden Code 暴力
Hidden Code 题目连接: http://codeforces.com/gym/100015/attachments Description It's time to put your hac ...
- Codeforces gym 100685 A. Ariel 暴力
A. ArielTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100685/problem/A Desc ...
- Codeforces Gym 100637G G. #TheDress 暴力
G. #TheDress Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100637/problem/G ...
随机推荐
- windows右键菜单自动打包发布nuget,没有CI/CD一样方便!
构建现代的 .Net 应用离不开 Nuget 的支持,而快速打包 Nuget 成了提高生产率的有效方法.没有CI/CD?来试试使用windows右键菜单吧 先看右键效果图 有时候我们可能没有CI/CD ...
- SharkCTF2021 The_nature_of_the_human
(信安数基的quiz1写不出来 来这放题解泄愤) crypto类题. 题面 其加密的大致过程是,对明文flag中的逐个字符,随机使用三种加密方式: 第一种,对该字符进行sha256加密后以16进制形式 ...
- 【Java虚拟机4】Java内存模型(硬件层面的并发优化基础知识--缓存一致性问题)
前言 今天学习了Java内存模型第一课的视频,讲了硬件层面的知识,还是和大学时一样,醍醐灌顶.老师讲得太好了. Java内存模型,感觉以前学得比较抽象.很繁杂,抽象. 这次试着系统一点跟着2个老师学习 ...
- 封装一个的toast弹出框(vue项目)
逆风的方向,更适合飞翔 实现效果 实现步骤 先写出一个toast组件 // Toast.vue <template> <div id="toast" :class ...
- Elasticsearch 中为什么选择倒排索引而不选择 B 树索引
目录 前言 为什么全文索引不使用 B+ 树进行存储 全文检索 正排索引 倒排索引 倒排索引如何存储数据 FOR 压缩 RBM 压缩 倒排索引如何存储 字典树(Tria Tree) FST FSM 构建 ...
- JVM:类加载与字节码技术-1
JVM:类加载与字节码技术-1 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 类文件结构 字节码指令 下面的内容在后续笔记中: 编译期处理 类加载阶段 类 ...
- 四万字32图,Kafka知识体系保姆级教程宝典
本文目录: 一.消息队列 Apache Pulsar Pulsar 与 Kafka 对比 二.Kafka基础 三.Kafka架构及组件 四.Kafka集群操作 五.Kafka的JavaAPI操作 六. ...
- mongodb的简单查询
此篇文章简单的记录一下mongodb 的简单查询操作. 一.数据准备: db.persons.insertMany([ {'userId':1,name:'张三','age':20,'scores': ...
- 海思 core 电压动态调整
http://www.eda365.com/forum.php?mod=viewthread&tid=108620&_dsign=5bee4dcb http://www.eda365. ...
- hdu 1160 FatMouse's Speed(最长不下降子序列+输出路径)
题意: FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to ...