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

ⅰ亾dé卋堺 提交于 2020-02-09 18:01:53

题意:有 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;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!