非傳統題初探——AtCoder Practice Contest #B - インタラクティブ練習 (Interactive Sorting)


原題:

Time limit : 2sec / Memory limit : 256MB

Score : 300 points

Problem Statement

This is an interactive task.

There are N balls labeled with the first N uppercase letters. The balls have pairwise distinct weights.

You are allowed to ask at most Q queries. In each query, you can compare the weights of two balls (see Input/Output section for details).

Sort the balls in the ascending order of their weights.

Constraints

  • (N,Q)=(26,1000)(26,100), or (5,7).

Partial Score

There are three testsets. Each testset is worth 100 points.

  • In testset 1, N=26 and Q=1000.
  • In testset 2, N=26 and Q=100.
  • In testset 3, N=5 and Q=7.

Input and Output

First, you are given N and Q from Standard Input in the following format:

N Q

Then, you start asking queries (at most Q times). Each query must be printed to Standard Output in the following format:

? c1 c2

Here each of c1 and c2 must be one of the first N uppercase letters, and c1 and c2 must be distinct.

Then, you are given the answer to the query from Standard Input in the following format:

ans

Here ans is either < or >. When ans is <, the ball c2 is heavier than the ball c1, and otherwise the ball c1 is heavier than the ball c2.

Finally, you must print the answer to Standard Output in the following format:

! ans

Here ans must be a string of length N, and it must contain each of the first N uppercase letters once. It must represent the weights of the balls in the ascending order.

Judgement

  • After each output, you must flush Standard Output. Otherwise you may get TLE.
  • After you print the answer, the program must be terminated immediately. Otherwise, the behavior of the judge is undefined.
  • When your output is invalid or incorrect, the behavior of the judge is undefined (it does not necessarily give WA).

題目大意:

這是一道交互題。有$N$個小球,用前$N$個大寫字母編號,每個小球有不同的重量。

最多允許詢問$Q$次。每次詢問可以比較兩個小球的重量。

按升序輸出小球的質量。

一共有三組數據(子任務),每組數據100分。數據規模如下:

子任務編號 $N$ $Q$
$1$ $26$ $1000$
$2$ $26$ $100$
$3$ $5$ $7$

注意事項:

  1. 輸出一次就要刷新一次標准輸出,否則可能會被誤判為TLE;
  2. 輸出答案后,程序必須立即退出,否則judger的行為未定義;
  3. 若輸出答案不符合格式或不正確,judger的行為未定義(不一定給出WA)。

題解:

第一次做交互題,感覺很新鮮,但是不知道該怎么做。首先程序要與交互庫進行交互,根據交互庫給出的信息判斷小球的質量情況。

對於第一個子任務,由於$Q$的范圍很大,直接詢問$26^2$次進行一次選擇排序就可以了。

對於第二個子任務,由於詢問次數只有$100$次,我們假設數組已經有序,二分一個小球質量的位置為$mid$,然后與這個位置的小球的質量進行比較,進行一次插入排序即可。需要詢問$26\log_226$次,還是不能通過所有的數據。這就要求我們需要對每一次詢問的答案做一個記憶化處理,記錄下詢問小球的質量關系,然后根據這個質量關系就可以得出有序的數列,從而降低時間復雜度,當然如果不記憶化也有可能能夠通過這道題目($123$次詢問只比限制大一點)。

也可以寫一個歸並排序之類的東西。當然需要記憶化,記憶化每一個數大於哪些數小於哪些數(或者只記憶化比這個數大的最小的數與比這個數小的最大的數)。

對於第三個子任務,注意到這組數據非常特殊,其實與給$5$個小球,最多稱$7$次求出質量關系的問題相同。可以自己思考一下詢問次數最小的方案。

#include<bits/stdc++.h>
using namespace std;

char s[29], ans[29];
int cmp['Z'+5]['Z'+5];
int cnt = 0, QQ = 1;

bool cmp_user(const char a, const char b) {
	char cp;
	if(cmp[a][b]==-1) {
		printf("? %c %c\n", a, b);
		fflush(stdout);
		scanf(" %c", &cp);
		if(cp=='>') {
			cmp[a][b] = true;
			cmp[b][a] = false;
			return true;
		}
		else {
			cmp[a][b] = false;
			cmp[b][a] = true;
			return false;
		}
	}
	else return cmp[a][b];
}

void ins2(char c) {
	if(cmp_user(c, s[1])) {
		if(cmp_user(c, s[2])) s[3] = c;
		else s[3] = s[2], s[2] = c;
	} else {
		if(cmp_user(c, s[0])) {
			s[3] = s[2];
			s[2] = s[1];
			s[1] = c;
		} else {
			s[3] = s[2];
			s[2] = s[1];
			s[1] = s[0];
			s[0] = c;
		}
	}
}

void ins(char c) {
	int l = 0, r = cnt;
	while(l<r) {
		int mid = l+r>>1;
		if(cmp_user(c, ans[mid])) l = mid+1;
		else r = mid;
	}
	cnt ++;
	if(cmp_user(c, ans[r])) r ++;
	for(int i=cnt; i>=r+1; i--) ans[i] = ans[i-1];
	ans[r] = c;
}

int main() {
	int N, Q;
	scanf("%d%d", &N, &Q);
	
	for(int i=0; i<26; i++) s[i] = (char)(i+'A');
	s[N] = '\0';
	
	if(N==26) {
		memset(cmp, -1, sizeof(cmp));
		cnt = 0;
		ans[0] = s[0];
		ans[N] = '\0';
		for(int i=1; i<N; i++) ins(s[i]);
		
		printf("! %s\n", ans);
	} else {
		memset(cmp, -1, sizeof(cmp));
		if(cmp_user(s[0], s[1])) swap(s[0], s[1]);
		if(cmp_user(s[2], s[3])) swap(s[2], s[3]);
		if(cmp_user(s[1], s[3])) {
			swap(s[0], s[2]);
			swap(s[1], s[3]);
		}
		char x = s[2];
		if(cmp_user(s[4], s[1])) {
			if(cmp_user(s[4], s[3])) {
				s[2] = s[3];
				ins2(x);
			} else {
				s[2] = s[4];
				s[4] = s[3];
				ins2(x);
			}
		} else {
			if(cmp_user(s[4], s[0])) {
				s[2] = s[1];
				s[1] = s[4];
				s[4] = s[3];
				ins2(x);
			} else {
				s[2] = s[1];
				s[1] = s[0];
				s[0] = s[4];
				s[4] = s[3];
				ins2(x);
			}
		}
		printf("! %s\n", s);
	}
	return 0;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM