这是一道交互题
给定正整数 (n),交互器有长为 (n) 的排列 (A),你需要实现以下函数求出 (A):
- ( exttt{int query_permutation(int n, int ans[])}):
- (n) 表示排列长度。
- (ans) 是一个
int
数组,若能求出答案,你需要将 (A_i) 存到 (ans[i]) 作为结果并返回 (1),否则返回 (0)。
你可以调用以下函数来与交互器进行交互:
- ( exttt{void new_round()}):
- 调用这个函数后,开启一轮新的实验的第 (1) 阶段,交互器生成 (2n) 个点的无向图,初始有 (n) 条边,分别为 ((i,A_i+n))。
- 你至多能调用这个函数 (2) 次。
- ( exttt{void next_step()}):
- 调用这个函数后,进入实验的下一阶段。
- 你只能在实验的第 (1) 阶段调用这个函数。
- ( exttt{void addedge(int u, int v)}):
- 你需要保证 (u,vin[1,n])。
- 交互器在图上连一条边 ((u,v))。
- 你只能在实验的第 (1) 阶段调用这个函数。
- 对于每一组数据,你至多能调用这个函数 (2(n-1)) 次。
- ( exttt{int query(int u, int v)}):
- 你需要保证 (u,vin[1,n])。
- 若 (u+n) 与 (v+n) 在图上连通,则返回 (1)。否则返回 (0)。
- 你只能在实验的第 (2) 阶段调用这个函数。
- 对于每一组数据,你至多能调用这个函数 (2cdot 10^6) 次。
(T) 组数据。(Tle 10,nle 10^4)。
首先无解当且仅当 (n=2),因为当 (n>2) 时可以搞一个暴力:第一次 ((1,2),(3,4),cdots),第二次 ((2,3),(4,5),cdots)。
然而这个需要查询 ( exttt{query}) (O(n^2)) 次,究其原因是连通块数量太多,每次查询一个点所在连通块大概需要 (O()连通块数()) 次。因此我们要尽量减少连通块数。
于是可以得到一个想法:把点排成方阵,多余的单开一列,第一次查询行连通性,第二次查询列连通性。
这显然很不行,因为行、列之间调换下顺序你就看不出来了,因此我们需要能直接看出所在连通块的构造方案:
可以先把列孤立点 (B) 所在行求出来,之后每个点可以通过所在连通块大小确定。
( exttt{query}) 次数 (O(nsqrt n)),常数不会算,但是可过(
#include"worldline.h"
#include<bits/stdc++.h>
using namespace std;
const int N = 10003;
int m, k, rt[N], S[N], c[2][N], s[2][N];
void work(int n, int c[N], int s[N]){
next_step(); k = 0;
for(int i = 1, j;i <= n;++ i){
for(j = 1;j <= k;++ j) if(query(i, rt[j])){c[i] = j; ++ s[j]; break;}
if(j > k){rt[++k] = i; c[i] = k; s[k] = 1;}
}
}
int query_permutation(int n, int ans[]){
if(n == 2) return 0;
if(n == 1){ans[1] = 1; return 1;}
for(m = 1;;++ m){S[m] = S[m-1] + m; if(S[m] >= n) break;}
S[m] = n; new_round();
for(int i = 1;i <= m;++ i)
for(int j = S[i-1]+1;j < S[i];++ j) addedge(j, S[i]);
work(n, c[0], s[0]); new_round();
for(int i = 1;i < m;++ i)
for(int j = i;j < m-1;++ j) addedge(S[j] + i, S[i]);
for(int i = 1;i < S[m] - S[m-1];++ i) addedge(n - i, S[m - i]);
work(n, c[1], s[1]);
if(S[m] - S[m-1] < m){ int u;
for(u = 1;u <= n;++ u)
if(s[0][c[0][u]] == S[m] - S[m-1] && s[1][c[1][u]] == 1) break;
for(int i = 1;i <= n;++ i) if(c[0][i] == c[0][u]){
ans[n - s[1][c[1][i]] + 1] = i; -- s[1][c[1][i]];
} -- m; s[0][c[0][u]] = 0;
} for(int i = 1;i <= n;++ i) if(s[0][c[0][i]])
ans[S[s[0][c[0][i]] - 1] + m - s[1][c[1][i]] + 1] = i;
return 1;
}