[TIOJ] 1945. 小向的試煉 1-1:猜謎遊戲(Guessing)

題目連結:http://tioj.infor.org/problems/1945
這題看到他詢問的次數後,應該很容易想到我們的上限就是$N+\log_2 N+2$,那那$N$必定是先單點詢問一遍,然後$\log_2 N$就是二分搜誰說謊,值得注意的是,你發現右半塊沒問題後不能又去問左半塊,要直接問左半塊的小孩,不然Query的次數會變成$2 \times N$,如果要確認會不會CE之類的話或詢問太多次,可以複製我下面的標頭檔,大概這樣吧
#include <cstdio>
#define N 131072
#include "lib1945.h"

int q[N+5]; 
int arr[N+5];

int sum[N+5];

inline int query(int l,int r){
	return (l==0)?sum[r-1]&1:(sum[r-1]-sum[l-1])&1;
}

inline void check(int l, int r){
	if(r-l==1){
		int k = Query(1,q+l);
		if(k!=query(l,l+1))
			arr[l]=Query(1,q+l);
	}else{
		int m=(l+r)/2;
		int fromXian = Query(m-l, q+l);
		int fromOrigin = query(l,m);
		if(fromOrigin == fromXian)
			check(m,r);
		else
			check(l,m);
	}
	
}

int main(){
	Init();
	for(int i=0;i<N;i++)
		q[i]=i;
	for(int i=0;i<N;i++)
		arr[i]=Query(1,q+i);
	sum[0]=arr[0];
	for(int i=1;i<N;i++)
		sum[i] = sum[i-1]+arr[i];
	check(0,N);
	for(int i=0;i<N;i++)
		printf("%d ",arr[i]);
	return 0;
}
附上我自己在用的lib1945.h
#include <cstdio>
#include <cstdlib>
#include <ctime>
#define __N__ 131072
int __arr__[__N__];
bool __ttff__=0;
int __C__=0;

void Init(){
	srand(time(NULL));
	for(int i=0;i<__N__;i++)
		__arr__[i]=rand()%2;
}

int Query(int n,int a[]){
	int count=0;
	for(int i=0;i<n;i++)
		count+=__arr__[a[i]];
	if(!__ttff__&&rand()%50==1){
		__ttff__=1;
		return (count+1)%2;
	}
	//printf("C:%d\n",++__C__);
	return count%2;
}

留言

這個網誌中的熱門文章

[NPSC] 2009初賽 E. 檸檬汽水傳說

[TIOJ] 1902. 「殿仁.王,不認識,誰啊?」,然後他就死了……

[AtCoder] [經典競程 90 題] 024 - Select +/- One(★2)