loj #6136. 「2017 山东三轮集训 Day4」Left

题目:

1055088-20170707161325894-115966358.png

题解:

我们可以发现所有的交换器都是一个位置连接着下一层左侧的排序网络,另一个位置连着另一侧的排序网络。
而下一层是由两个更低阶的排序网络构成的。
两个网络互不干扰。所以我们可以通过第一行和最后一行列出多个2-SAT的约束限制。
所以我们可以在每一次都跑一边2-SAT来决策出最外层的交换器是否开启。
然后我们就可以发现每次2-SAT都一定有解,也就是说不可能出现无解的情况。
用2-SAT保证字典序最小即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
    x=0;static char ch;static bool flag;flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 40010;
struct Node{
    int to,next;
}G[maxn<<1];
int head[maxn],cnt;
void add(int u,int v){
    G[++cnt].to = v;
    G[cnt].next = head[u];
    head[u] = cnt;
}
inline void clear_G(){
    memset(head,0,sizeof head);
    cnt = 0;
}
bool mark[maxn];
int n,sta[maxn],top,m;
inline int rev(int u){
    return u^1;
}
#define v G[i].to
bool dfs(int u){
    if(mark[u]) return true;
    if(mark[u^1]) return false;
    mark[u] = true;sta[++top] = u;
    for(rg i = head[u];i;i=G[i].next){
        if(dfs(v) == false) return false;
    }return true;
}
#undef v
inline bool clear(){
    top = 0;clear_G();
}
int p[maxn],ws[maxn];
bool ans[128][9010];
inline int get(int x,int m){
    return (x >> 1) | ((x&1) << m-1);
}
int a[maxn],b[maxn],c[maxn];bool solve_next;
int main(){
    while(1){
        clear();read(m);if(m == 0) break;
        n = 1 << m;int lim = ((n-1) >> 1)+1;
        rep(i,0,n-1) read(p[i]),ws[p[i]] = i,a[i] = i;
        for(rg k = m;k > 1; -- k){
            memset(mark,false,sizeof mark);
            clear_G();
            int sz = 1 << k,l = 0,r = 0;
            rep(i,0,n-1){
                b[i] = a[i];c[i] = p[i];
                if((i-l+1) == sz){
                    r = i;
                    int mid = l+r >> 1;
                    rep(j,l,r){
                        if((get(j-l,k)+l <= mid) != (get(ws[a[j]]-l,k)+l <= mid)){
                            int x = j >> 1,y = ws[a[j]] >> 1;
                            add(x<<1,(y+lim)<<1|1);add((y+lim)<<1|1,x<<1);
                            add(x<<1|1,(y+lim)<<1);add((y+lim)<<1,x<<1|1);
                        }else{
                            int x = j >> 1,y = ws[a[j]] >> 1;
                            add(x<<1,(y+lim)<<1);add((y+lim)<<1,x<<1);
                            add(x<<1|1,(y+lim)<<1|1);add((y+lim)<<1|1,x<<1|1);
                        }
                    }l = i+1;r = 0;
                }
            }
            rep(i,0,n-1){
                top = 0;
                if(dfs(i<<1) == false){
                    while(top) mark[sta[top--]] = false;
                    if(dfs(i<<1|1) == false){
                        solve_next = true;
                        break;
                    }
                }if(solve_next) break;
            }if(solve_next) break;
            l = 0;
            rep(i,0,n-1){
                if((i - l + 1) == sz){
                    rep(j,l,i){
                        int x = j >> 1;
                        if(mark[x<<1|1]){
                            ans[m-k][x] = 1;
                            a[get((j^1)-l,k)+l] = b[j];
                        }else{
                            ans[m-k][x] = 0;
                            a[get(j-l,k)+l] = b[j];
                        }
                        x = (j >> 1) + lim;
                        if(mark[x<<1|1]){
                            ans[m+k-2][x-lim] = 1;
                            p[get((j^1)-l,k)+l] = c[j];
                        }else{
                            ans[m+k-2][x-lim] = 0;
                            p[get(j-l,k)+l] = c[j];
                        }
                    }l = i+1;
                }
            }
            rep(i,0,n-1) ws[p[i]] = i;
        }
        if(solve_next){
            solve_next = false;
            puts("-1");
            continue;
        }
        rep(i,0,n-1){
            if(a[i] == p[i] && a[i^1] == p[i^1]) ans[m-1][i>>1] = 0;
            else if(a[i] == p[i^1] && a[i^1] == p[i]) ans[m-1][i>>1] = 1;
            else {solve_next = true;break;}
        }
        if(solve_next){puts("-1");continue;}
        rep(i,0,2*m-2){
            rep(j,0,(n-1)>>1){
                printf("%d",ans[i][j]);
            }puts("");
        }puts("");
    }
    return 0;
}

转载于:https://www.cnblogs.com/Skyminer/p/7132824.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值