zoukankan      html  css  js  c++  java
  • 题解 CF1514E Baby Ehab's Hyper Apartment [*medium]

    能在场上想出来自己不怎么擅长的交互题还是比较开心的(

    但是因为不了解 Extra Registration(在 (30) 分钟之后就不能报名了),没能交上去。。。

    题面

    给定一张 (n) 个点竞赛图,你可以进行一些询问,询问有两种:

    • (1) (a) (b):查询是否有从 (a)(b) 的有向边。这种询问次数 (le 9n)
    • (2) (x) (k) (s_1) (s_2) (...) (s_k) : 查询 (x)(s_1)(s_2),...,(s_k) 是否存在一条有向边。这种询问次数 (le 2n)

    最后要求输出对于所有 ((i, j)),是否有 (i)(j)路径。多测。

    题解

    众所周知把竞赛图缩点之后形成的强联通分量是一条链,如果知道了这些的强联通分量就可以得出答案。

    接下来分成两个步骤:

    1. 找到一条包括 (1, 2, ..., n) 的路径。

    2. 在这条路径上进行缩点。

    步骤1

    考虑增量,设这条链原先是 (v_1, v_2, ..., v_k),现在要加入点 (k)

    因此要找出一个位置 (p)(1 le p le k + 1)) 满足有一条从 (v_{p-1})(k) 的边且有一条从 (k)(v_p) 的边,并在 (p) 之前插入 (k)

    如果有从 (v_{l-1})(k) 的边且有从 (k)(v_r) 的边,那么可以在 ([l, r]) 找到答案。

    考虑二分答案,如果有 (k)(v_{mid}) 的边那么在 ([l,mid]) 中可以找到答案,否则在 ([mid+1, r]) 种可以找到答案。

    需要 (n log n) 个询问 (1)

    步骤2

    设目前缩出来的链是 (S_1 o S_2 o ... o S_k)

    从后往前缩点,对于一个 (S_t) 中的点 (z),如果存在一条从 (S_1, S_2, ..., S_{t - 1}) 的点到 (z) 的边(可以利用询问 (2) 查询),那么 (S_t)(S_{t-1}) 必然在一个集合中。

    不停地这样缩点即可得到最终答案。需要 (2n) 个询问 (2)

    代码

    #include<bits/stdc++.h>
    #define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++)
    #define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--)
    #define ll long long
    #define pii pair<int, int>
    #define db double
    #define x first
    #define y second
    #define ull unsigned long long
    #define sz(a) ((int) (a).size())
    #define vi vector<int>
    using namespace std;
    const int N = 233;
    int n, tot, v[N];
    set < int > S[N];
    void merge(int x, int y) {
    	for(int k : S[y]) S[x].insert(k);
    	S[y].clear();
    }
    int getin() {
    	int k;
    	return cin >> k, k;
    }
    bool check(int x, int y) {
    	return cout << 1 << " " << x << " " << y << endl, getin();
    }
    bool all[N][N], vis[N];
    int rmain() {
    	memset(all, 0, sizeof(all)), memset(vis, 0, sizeof(vis)), memset(v, 0, sizeof(v));
    	L(i, 1, tot) S[i].clear();
    	tot = 0;
    	cin >> n;
    	L(i, 0, n - 1) {
    		int l = 1, r = tot + 1;
    		while(l < r) {
    			int mid = (l + r) >> 1;
    			if(mid == tot + 1 || check(i, v[mid])) r = mid;
    			else l = mid + 1;
    		}
    		R(i, tot, l) v[i + 1] = v[i];
    		++tot, v[l] = i;
    	}
    	L(i, 1, tot) S[i].insert(v[i]);
    	int now = tot;
    	while(now > 1) {
    		for(int v : S[now]) if(!vis[v]) {
    			cout << 2 << " " << v << " ";
    			int cnt = 0;
    			L(i, 1, now - 1) cnt += sz(S[i]);
    			cout << cnt << " ";
    			L(i, 1, now - 1) for(int u : S[i]) cout << u << " ";
    			cout << endl;
    			if(getin()) {
    				merge(now - 1, now);
    				break;	
    			}
    			vis[v] = true;
    		}
    		--now;
    	}
    	L(i, 1, tot) L(j, i, tot) for(int u : S[i]) for(int v : S[j]) all[u][v] = true;
    	cout << 3 << endl;
    	L(i, 0, n - 1) {
    		L(j, 0, n - 1) cout << all[i][j];
    		cout << endl;	
    	} 
    	return getin(), 0;
    }
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(0); cout.tie(0);
    	int T;
    	cin >> T;
    	while(T--) rmain();
    	return 0;
    } 
    

    祝大家学习愉快!

  • 相关阅读:
    BLE编程中关键步骤
    gradle相关配置内容解析
    Gradle版本变更的问题
    【问题】AndroidStudio导入项目一直卡在Building gradle project infod的最快速解决方案
    jdbc.properties各种数据库连接配置
    EL表达式语言总结
    Android sdk目录介绍
    chrome的常用快捷键和命令
    Unity Hub for Mac 破解
    MAC下安装配置Tomcat
  • 原文地址:https://www.cnblogs.com/zkyJuruo/p/14679797.html
Copyright © 2011-2022 走看看