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(分块暴力+完全图的链覆盖)的更多相关文章

  1. Codeforces Beta Round #13 E. Holes 分块暴力

    E. Holes Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/13/problem/E Des ...

  2. Codeforces#86D Powerful array(分块暴力)

    Description An array of positive integers a1, a2, ..., an is given. Let us consider its arbitrary su ...

  3. Codeforces Round #616 Coffee Varieties

    题意 不太容易讲清,看英文吧 codeforces 做法 先从简单的看起 将块以\(\frac{k}{2}\)个元素为界,然后类似线段树一样递归下去,每次一层的左子树跟右子树的块相互暴力比较 \[\b ...

  4. (分块暴力)Time to Raid Cowavans CodeForces - 103D

    题意 给你一段长度为n(1 ≤ n ≤ 3·1e5)的序列,m (1 ≤ p ≤ 3·1e5)个询问,每次询问a,a+b,a+2b+...<=n的和 思路 一开始一直想也想不到怎么分,去维护哪些 ...

  5. D. Alyona and a tree 公式转换 + 分块暴力

    http://codeforces.com/problemset/problem/740/D 对于每一对<u, v>.设dis[u]表示root到点u的距离,那么dis<u去v> ...

  6. Codeforces 1129D - Isolation(分块优化 dp)

    Codeforces 题目传送门 & 洛谷题目传送门 又独立切了道 *2900( 首先考虑 \(dp\),\(dp_i\) 表示以 \(i\) 为结尾的划分的方式,那么显然有转移 \(dp_i ...

  7. Codeforces Gym 100015H Hidden Code 暴力

    Hidden Code 题目连接: http://codeforces.com/gym/100015/attachments Description It's time to put your hac ...

  8. Codeforces gym 100685 A. Ariel 暴力

    A. ArielTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100685/problem/A Desc ...

  9. Codeforces Gym 100637G G. #TheDress 暴力

    G. #TheDress Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100637/problem/G ...

随机推荐

  1. 【UE4 C++】抛物线路径、发射轨道相关

    基于UGameplayStatics Blueprint_PredictProjectilePath_ByObjectType 根据 Object Type,算出抛物线的点集合和检测结果 static ...

  2. UltraSoft - Alpha - Postmortem 事后分析

    Alpha阶段 Postmortem会议 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 主要是解决DDL提醒功能的问题,定义的比较清楚,对典型用户和典 ...

  3. Noip模拟12 2021.7.12

    T1 interval 亏得昨天晚上改掉了T3并且理解了单调栈,今天一扫这题目就知道要用啥了. 先预处理出以a[i]为最大值的最大左右区间.然后再将a[i]取%!!!是的,要不然会影响单调栈的使用.. ...

  4. 数字在排序数组中出现的次数 牛客网 剑指Offer

    数字在排序数组中出现的次数 牛客网 剑指Offer 题目描述 统计一个数字在排序数组中出现的次数. class Solution: def GetNumberOfK(self, data, k): i ...

  5. Django 开发------django-crontab实现服务端的定时任务

    一.需求: 想实现类似 Linux 中crontab 的功能.定时执行计划任务. 二.配置: a.安装插件: # pip3 install django-crontab b.在settings.py ...

  6. Redis源码分析(skiplist)

    源码版本: redis-4.0.1 源码位置: server.h :zskiplistNode和zskiplist的数据结构定义. t_zset.c: 以zsl开头的函数是SkipList相关的操作函 ...

  7. TTMS 一个基于Java Swing的Socket通信的剧院票务管理系统

    TTMS (Theater Ticket Management System) 点我进入github TTMS全称剧院票务管理系统,分为客户端和服务器端.服务器端可以接收客户端连接请求,客户端相当于我 ...

  8. Java测试开发--sts安装Lombok(七)

    1.sts安装Lombok的步骤: 下载最新的lombok.jar包,进入cmd窗口,切到Lombok下载的目录,运行命令: java -jar lombok.jar,会出现如下界面: 已经默认选好了 ...

  9. vs Code配置C++运行和调试环境以及相关问题

    vs Code配置C++运行和调试环境以及相关问题 第一步:下载c++插件 第二步:安装编译.调试环境 如果没有Dev-C++下载MinGW 下载地址:https://sourceforge.net/ ...

  10. 使用Abp vnext构建基于Duende.IdentityServer的统一授权中心(一)

    原来看到很多示例都是基于IdentityServer4的统一授权中心,但是IdentityServer4维护到2022年就不再进行更新维护了,所以我选择了它的升级版Duende.IdentitySer ...