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 ...
随机推荐
- Redis使用过程中有哪些注意事项?看看BAT这类的公司是正确使用Redis的!!
Redis使用过程中要注意的事项 Redis使用起来很简单,但是在实际应用过程中,一定会碰到一些比较麻烦的问题,常见的问题有 redis和数据库数据的一致性 缓存雪崩 缓存穿透 热点数据发现 下面逐一 ...
- Linux常用命令查看文件、别名、切换目录、创建目录、查看当前目录
一.创建条件(使用liunx常用命令): 1.查看阿里云的环境是否搭建完成 首先快捷键 win+R 输入cmd 回车,打开命令提示符输入命令 ssh,回车. 2.登录阿里云账户 输入命令格式:ssh ...
- js 原型链详解
目录 构造函数和实例 属性Prototype 属性__proto__ 访问原型上的方法 构造函数也有__proto__ 构造函数的原型也有__proto__ Object.prototype这个原型对 ...
- hdu 2200 Eddy's AC难题(简单数学。。)
题意: N个人,每个人AC的题数都不一样. Eddy想从中选出一部分人(或者全部)分成两组.必须满足第一组中的最小AC数大于第二组中的最大AC数. 问共有多少种不同的选择方案. 思路: 简单数学.. ...
- Win powershell执行策略配置
参考连接:https://blog.csdn.net/jeffxu_lib/article/details/84710386 参考连接:http://www.cragsman.org/index.ph ...
- 装了这几个IDEA插件,基本上一站式开发了!
前言 前几天有社区小伙伴私聊我,问我都用哪些IDEA插件,我的IDEA的主题看起来不错. 作为一个开源作者,每周要code大量的代码,提升日常工作效率是我一直追求的,在众多的IDEA插件中,我独钟爱这 ...
- SpringBoot2.x请求注解简单介绍(4)
1.新建项目,项目中实战讲解注解作用 2.pom.xml依赖配置 <properties> <project.build.sourceEncoding>UTF-8</pr ...
- js运算符 及 运算符优先级
「运算符」是用于实现赋值.比较和执行算数运算等功能的符号.常用运算符分类如下符号 算数运算符 递增和递减运算符 比较运算符 逻辑运算符 赋值运算符 算数运算符 运算符 描述 案例 + 加 10+20= ...
- JSON数据和Java对象的相互转换
JSON解析器: 常见的解析器: Jsonlib, Gson, fastjson, jackson 其中应用最广泛的是jackson,阿里的fastjson虽然比jackson快一点,但存在的问题比较 ...
- Spark中的两种模式
两种模式 client-了解 cluster模式-开发使用 操作 1.需要Yarn集群 2.历史服务器 3.提交任务的的客户端工具-spark-submit命令 4.待提交的spark任务/程序的字节 ...