Codeforces Round #616 (Div. 1) - D . Coffee Varieties (hard version) (1290D)

题意:有 n 家咖啡馆,每家咖啡店有一种咖啡,有些店的咖啡种类一样,你的朋友有 k 次记忆,你每次可以让你的朋友去一家咖啡馆喝咖啡,他会告诉你这个咖啡在之前的 k 次记忆中有没有喝过,你还有 h(<=30000) 次机会重置你朋友的记忆,在询问次数不超过 3*n^2 / 2k 的情况下,统计出共有多少种不同的咖啡;

 

分析:最暴力的方法是两两询问然后重置记忆,这样需要询问 (n-1)! 次,重置 (n-1)! 次,肯定会T,考虑有 n 种 咖啡的状态,所以我们必须每两家咖啡店都至少比较一次。因为你的朋友有 k 次记忆,则我们可以把 n 家咖啡馆分成 n/k 组,每组长度为 k ,只要每两组之间在询问中相邻过两次,并且两次前后顺序不同,那么就相当于这两组每两家咖啡店都比较了一次。。那么 问题来了,怎么让每两组分组在合理的询问次数内相邻两次且前后顺便不同呢,这个就得用到 zig-zag 顺序(x,x-1,x+1,x-2,x+2...),让分组按照这样的顺序询问 n 个咖啡店,并对重复出现的点标记(标记过后再不询问),每次询问完一遍后重置记忆,这样只要重置 n/k 次记忆,询问 n*n/k 次,就可以统计出有多少种不同的咖啡了。

 

代码:

#include<vector>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

bool ask(int pos)
{
	cout<<"? "<<pos+1<<endl<<flush;
	char c; cin>>c;
	return c=='Y';
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,k,p;
	cin>>n>>k; p=n/k;
	vector<bool>cnt(n,true);
	
	for(int i=0;i<p;i++){
		int shift=0;
		for(int j=0;j<p;j++){
			int now=(i+shift+p)%p;
			int bg=k*now;
			for(int z=bg;z<bg+k;z++){
				if(cnt[z]){
					if(ask(z)) cnt[z]=false;
				}
			}
			if(shift>=0) shift++;
			shift=-shift;
		}
		cout<<"R "<<endl<<flush;
	}
	int ans=count(cnt.begin(),cnt.end(),true);
	cout<<"! "<<ans<<endl<<flush;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值