• Codeforces Round #812 (Div. 2)


    Codeforces Round #812 (Div. 2)

    E. Cross Swapping (扩展域并查集解决2-SAT)


    引用一段关于扩展域并查集的总结:

    并查集分两种:带边权和扩展域

    带边权:带边权的并查集维护的是相对关系,也就是相对于根的关系, 能用并查集来做个核心思想有两点,第一点就是关系具有传递性, 也就是说,如果已知 x , y x,y x,y 的关系也知道 y , z y,z y,z 的关系,那么必然知道 x , z x,z x,z 的关系第二点是要必须具有对称性,无向边 a a a 能到 b b b 同时 b b b 也能到 a a a

    扩展域:维护的是多组关系。怎么理解呢?这里有一种理解的方式就是:假如存在 x x x 种性质,一共有 n n n 个节点,那么对于每个物品 y y y 来说 f [ y ] f[y] f[y] 代表 y y y 是第一种性质, f [ y + n ] f[y + n] f[y+n]代表 y y y 是第二种性质 … f [ y + ( x − 1 ) n ] f[y + (x -1)n] f[y+(x1)n] 代表 y y y 是第 x x x 种性质。这不就是SAT吗

    ​ 如果处理关系和矛盾?以关押罪犯这道题为例,首先定义 f [ x ] f[x] f[x] 是犯人 x x x 所在的监狱, f [ x + n ] f[x + n] f[x+n] 是另一座监狱,如果这个时候我们要维护 a , b a, b a,b 不在一个监狱。就先判断如果 p [ f [ a ] ] = = p [ f [ b ] ] p[f[a]] == p[f[b]] p[f[a]]==p[f[b]] 那么就矛盾,否则就把 p [ f [ a ] ] = p [ f [ n + b ] ] p[f[a]] = p[f[n + b]] p[f[a]]=p[f[n+b]], p [ f [ b ] ] = p [ f [ n + a ] ] p[f[b]] = p[f[n + a]] p[f[b]]=p[f[n+a]] 意思就是把a所在的监狱与b不在的监狱合并,同时把 b b b 所在的监狱与 a a a 不在的监狱合并。


    每个点进行转置只有两个选择,换 or 不换。要求字典序最小,从前往后贪心。

    如果一个点一个点考虑就会麻烦,一行一行的考虑。

    i i i 表示换, i + n i+n i+n 表不换。本题需要快读 or scanf

    最后找一个起始点,非常巧妙。


    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define pb push_back 
    #define all(x) (x).begin(),(x).end()
    #define mem(f, x) memset(f,x,sizeof(f)) 
    #define fo(i,a,n) for(int i=(a);i<=(n);++i)
    #define fo_(i,a,n) for(int i=(a);i<(n);++i)
    #define debug(x) cout<<#x<<":"<<x<<endl;
    using namespace std;
    //#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math,O3")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    
    typedef pair<int,int>PII;
    typedef pair<long,long>PLL;
    
    typedef long long ll;
    typedef unsigned long long ull; 
    const int N=2e6+10,M=1e9+7;
    ll n,m,_;
    
    int a[1100][1100];
    int fa[2200];
    
    int find(int x){
        return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
    }
    
    void solve(){
    
    	cin>>n;
        fo(i,1,n*2)fa[i] = i;
        fo(i,1,n)fo(j,1,n)cin>>a[i][j];
        fo(i,1,n){
            fo(j,i+1,n){
                if(a[i][j] > a[j][i]){
                    int x = i,y = j;
                    int nx = x + n,ny = y + n;
                    if(find(nx) == find(ny)){
                        continue;
                    }
                    fa[find(x)] = find(ny);
                    fa[find(nx)] = find(y);
                }
                else if (a[i][j] < a[j][i]){
                    int x = i,y = j;
                    int nx = x + n,ny = y + n;
                    if(find(x) == find(ny)){
                        continue;
                    }
                    fa[find(x)] = find(y);
                    fa[find(nx)] = find(ny);
                }
            }
        }
        set<int>st;
        fo(i,1,n){
            if(fa[i] == i)st.insert(i);
        }
    	// i 是换的起始点 , st.size()一定为1
        fo(i,1,n){
            if(st.count(find(i))){ // 注意一定是find(i)
                fo(j,1,n){
                    swap(a[i][j],a[j][i]);
                }
            }
        }
        fo(i,1,n){
            fo(j,1,n){
                cout<<a[i][j]<<" ";
            }
            cout<<endl;
        }
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	cin>>_;
    	while(_--){
    		solve();
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    D. Tournament Countdown


    需要一些灵感 or 套路的题。

    场次要在 2 3 2 n {\frac{2}{3}2^n} 322n

    考虑:一共 2 n 2^n 2n 人,需要删掉 2 n − 1 2^n-1 2n1 人,想到 ?套路 两次可以从4个人中删掉3个人。

    2 ( 2 n − 1 ) 3 < 2 3 2 n \frac{2(2^n-1)}{3} < \frac{2}{3}2^n 32(2n1)<322n

    之后就是如何做到两次从4个人里边询问胜者。

    vKpM4A.png


    非常巧妙,询问 1 3。

    如果 1 > 3 , 又因为1和2要竞争1大于3的前提是1>2,所以淘汰了2,3。

    如果 1 < 3 , 同上淘汰了 1,4。

    如果 1 == 3 , 淘汰 1,3。


    /*
    A: 10min
    B: 20min
    C: 30min
    D: 40min
    */ 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define pb push_back 
    #define all(x) (x).begin(),(x).end()
    #define mem(f, x) memset(f,x,sizeof(f)) 
    #define fo(i,a,n) for(int i=(a);i<=(n);++i)
    #define fo_(i,a,n) for(int i=(a);i<(n);++i)
    #define debug(x) cout<<#x<<":"<<x<<endl;
    #define endl '\n'
    using namespace std;
    //#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math,O3")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    
    template<typename T>
    ostream& operator<<(ostream& os,const vector<T>&v){for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){j=0;puts("");}else os<<v[i]<<" ";return os;}
    template<typename T>
    ostream& operator<<(ostream& os,const set<T>&v){for(auto c:v)os<<c<<" ";return os;}
    template<typename T1,typename T2>
    ostream& operator<<(ostream& os,const map<T1,T2>&v){for(auto c:v)os<<c.first<<" "<<c.second<<endl;return os;}
    template<typename T>inline void rd(T &a) {
        char c = getchar(); T x = 0, f = 1; while (!isdigit(c)) {if (c == '-')f = -1; c = getchar();}
        while (isdigit(c)) {x = (x << 1) + (x << 3) + c - '0'; c = getchar();} a = f * x;
    }
    
    typedef pair<int,int>PII;
    typedef pair<long,long>PLL;
    
    typedef long long ll;
    typedef unsigned long long ull; 
    const int N=2e6+10,M=1e9+7;
    ll n,m,_;
    
    int ask(int x,int y){
        cout<<"? "<<x<<" "<<y<<endl;
        int res;cin>>res;
        return res;
    }
    
    void solve(){
        cin>>n;
        n = 1<<n;
        vector<int>a;
        fo(i,1,n)a.pb(i);
    
        // 4个四个询问
        while(a.size()>1){
            vector<int>b;
            if (a.size() == 2) {
                int t = ask(a[0], a[1]);
                if (t == 1)
                    b.push_back(a[0]);
                else
                    b.push_back(a[1]);
            }
            else{
    	        for(int i=0;i<a.size();i+=4){
    	            int x = a[i];
    	            int y = a[i+2];
    //	            debug(x);
    //	            debug(y);
    	            int res = ask(x,y);
    	            if(res == 1){
    	                res = ask(x,a[i+3]);
    	                if(res == 1){
    	                	res = x;
    	                }
    	                else res = a[i+3];
    	            }
    	            else if(res == 2){
    	                res = ask(a[i+1],y);
    	                if(res == 1){
    	                	res = a[i+1];
    	                }
    	                else res = y;
    	            }
    	            else{
    	                res = ask(a[i+1],a[i+3]);
    	                if(res == 1){
    	                	res = a[i+1];
    	                }
    	                else res = a[i+3];
    	            }
    	            b.pb(res);
    	        }
    	    }
            a = b;
        }
        cout<<"! "<<a[0]<<endl;
    }
    
    int main(){
    	cin>>_;
    	while(_--){
    		solve();
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
  • 相关阅读:
    Unity-huatuo热更新调研
    AspectJ AOP的使用(@Before、@PointCut、@Around等)
    postgresql分区表
    【React 源码】(十五)React Context 原理
    ciscn_2019_es_2【BUUCTF】
    Mybatis-Plus的使用
    IDEA SpringBoot-Mybatis-plus 实现增删改查(CRUD)
    ego-planner论文阅读笔记
    Eclipse:编译前自动保存文件
    王学岗约束性布局wrap_content失效的问题
  • 原文地址:https://blog.csdn.net/hacker__man/article/details/126208372