• 题解 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;
    } 
    

    祝大家学习愉快!

  • 相关阅读:
    LSMW TIPS
    Schedule agreement and Delfor
    Running VL10 in the background 13 Oct
    analyse idoc by creation date
    New Journey Prepare
    EDI error
    CBSN NEWS
    Listen and Write 18th Feb 2019
    Microsoft iSCSI Software Target 快照管理
    通过 Microsoft iSCSI Software Target 提供存储服务
  • 原文地址:https://www.cnblogs.com/zkyJuruo/p/14679797.html
Copyright © 2020-2023  润新知