• UOJ153【UR #10】世界线【交互、构造】


    这是一道交互题

    给定正整数 (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;
    }
    
  • 相关阅读:
    201771010108-韩腊梅 实验三 结对项目—《西北师范大学疫情防控信息系统》项目报告
    201771010108-韩腊梅 实验二 个人项目—《西北师范大学学生疫情上报系统》项目报告
    201771010108-韩腊梅 实验一 软件工程准备—<对软件工程的初步了解>
    201771010108 -韩腊梅-第十八周学习总结
    201771010108 -韩腊梅-第十七周学习总结
    201771010108 -韩腊梅-第十六周学习总结
    201771010108 -韩腊梅-第十五周学习总结
    2020软件工程-获得小黄衣有感
    201771030118-司绍斌 实验四 软件项目案例分析
    201771030118-司绍斌 实验三 结对项目—《西北师范大学疫情防控信息系统》项目报告
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/14587059.html
Copyright © 2020-2023  润新知