zoukankan      html  css  js  c++  java
  • [CF1343F] Restore the Permutation by Sorted Segments【构造】

    首先有一个观察:由于 (k_i>1),因此除了位置 (1)(n) 的数,其余的数都出现了至少 (2) 次。

    考虑从 (n)(1) 逐位确定,假设当前处理到第 (m) 位,会有以下几种情况:

    • 在未被占据的区间中,只有一个数 (x) 出现了 (1) 次;

    这种情况下,显然只能选择 (x) 作为第 (m) 位。

    • 有两个数 (x, y) 出现了 (1) 次,但 (x) 出现的区间长度 (geq 3)

    由于位置 (1) 的数必然会出现在 ([1, 2]) 中,因此 (x) 只能在位置 (m) 出现。

    • 有两个数 (x, y) 出现了 (1) 次,且出现的区间长度均 (=2)

    这时候我们无法直接判断谁出现在第 (m) 位,因此可以直接枚举并 dfs,直到找到一组合法解为止。

    乍一看这样的复杂度是指数级别的,但是注意到还有另外一个条件:若存在 (k>m),满足 (k) 出现的区间覆盖了位置 (m),那么 (m) 上的数必须在 (k) 出现的区间里。因此,如果我们在上一步中选择了向下 dfs,那么这一步实际上只有一个可能的数字(即上一步选择的区间覆盖的另一个元素),因此每到达一个分叉点后,都不会再出现新的分叉点,每一步中即使 (O(n)) 判断是否合法,实际复杂度也只有 (O(n^3)) 级别。

    Code:

    #include <bits/stdc++.h>
    #define R register
    #define mp make_pair
    #define ll long long
    #define pii pair<int, int>
    using namespace std;
    const int mod = 998244353, N = 210;
    
    int t, n, ans[N], bel[N];
    vector<int> seg[N];
    set<int> app[N];
    
    inline int addMod(int a, int b) {
    	return (a += b) >= mod ? a - mod : a;
    }
    
    inline ll quickpow(ll base, ll pw) {
    	ll ret = 1;
    	while (pw) {
    		if (pw & 1) ret = ret * base % mod;
    		base = base * base % mod, pw >>= 1;
    	}
    	return ret;
    }
    
    template <class T>
    inline void read(T &x) {
    	x = 0;
    	char ch = getchar(), w = 0;
    	while (!isdigit(ch)) w = (ch == '-'), ch = getchar();
    	while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    	x = w ? -x : x;
    	return;
    }
    
    int dfs(int m) {
    	int vis[N];
    	for (R int i = 1; i <= n; ++i) vis[i] = 0;
    	int num = 0;
    	for (R int i = m + 1; i <= n; ++i) {
    		if ((int) seg[bel[i]].size() <= i - m) continue;
    		++num, --vis[ans[i]];
    		for (auto &v : seg[bel[i]]) ++vis[v];
    	}
    	if (m == 1) {
    		for (R int i = 1; i <= n; ++i)
    			if (vis[i] == num) return ans[1] = i, 1;
    		return 0;
    	}
    	pii s(0, 0);
    	for (R int i = 1; i <= n; ++i) {
    		if (vis[i] != num || app[i].size() != 1) continue;
    		(s.first ? s.second : s.first) = i;
    	}
    	if (!s.first) return 0;
    	if (s.second && seg[*app[s.first].begin()].size() < seg[*app[s.second].begin()].size())
    		swap(s.first, s.second);
    	if (s.second && seg[*app[s.first].begin()].size() == 2) {
    		int w = *app[s.second].begin(), flag = 1;
    		for (auto &v : seg[w])
    			if (!app[v].size()) flag = 0;
    		if (flag) {
    			ans[m] = s.second, bel[m] = w;
    			for (auto &v : seg[w]) app[v].erase(w);
    			if (dfs(m - 1)) return 1;
    			for (auto &v : seg[w]) app[v].insert(w);
    		}
    	}
    	int w = *app[s.first].begin();
    	for (auto &v : seg[w])
    		if (!app[v].size()) return 0;
    	ans[m] = s.first, bel[m] = w;
    	for (auto &v : seg[w]) app[v].erase(w);
    	if (dfs(m - 1)) return 1;
    	for (auto &v : seg[w]) app[v].insert(w);
    	return 0;
    }
    
    int main() {
    	int x, y;
    	read(t);
    	while (t--) {
    		read(n);
    		for (R int i = 1; i < n; ++i) {
    			read(x), seg[i].clear();
    			while (x--) {
    				read(y), seg[i].push_back(y);
    				app[y].insert(i);
    			}
    		}
    		dfs(n);
    		for (R int i = 1; i <= n; ++i)
    			printf("%d ", ans[i]);
    		printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    sourcetree提交代码到远程仓库的方法
    使用sourcetree管理拉取代码的方法
    运用在伪类content上的html特殊字符
    H5在ios弹窗状态下调起输入法后关闭输入法页面元素错位解决办法
    Sticky footer经典布局--绝对底部布局
    Vue微信自定义分享时安卓系统config:ok,ios系统config:invalid signature签名错误,或者安卓和ios二次分享时均config:ok但是分享无效的解决办法
    如何在开发时用PC端对移动端页面进行调试
    SVN使用教程总结
    Keywords Search HDU2222 AC自动机模板题
    POJ
  • 原文地址:https://www.cnblogs.com/suwakow/p/12780070.html
Copyright © 2011-2022 走看看