zoukankan      html  css  js  c++  java
  • codeforces 1569 E. Playoff Restoration (meet-in-the-middle)

    题目链接:https://codeforces.com/contest/1569/problem/E

    如果有 (2^k) 个参赛选手,那么一共会进行 (2^k-1) 场比赛,搜索每场比赛的结果,判断是否满足条件就可以了,但当 (k=5) 时,(2^5=32),爆搜显然不行,可以使用 (meet-in-the-middle) 的技巧,将所有参赛队员分为两组,组内分别搜索,记录第一组所有的答案,第二组搜索时在第一组的答案中查询即可

    具体实现还有很多细节

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    
    const int maxn = 155;
    const int M = 998244353;
    const int base = 131;
    
    int n, k, A, h, tot, flag, f1, f2, t1, t2;
    int p[10], a[maxn][10], rk[maxn], c[maxn];
    
    map<int, int> mp;
    
    int qsm(int i, int po){
    	int res = 1;
    	while(po){
    		if(po & 1) res = 1ll * res * i % M;
    		i = 1ll * i * i % M;
    		po >>= 1;
    	}
    	return res;
    }
    
    int get_r(int d){
    	int tmp = d, r = k-2;
    	for(int i = k-2 ; i >= 0 ; --i){
    		if(tmp - (1<<i) > 0) {
    			tmp -= (1<<i);
    			--r;
    		}
    		else break;
    	}
    	return r;
    }
    
    void dfs1(int d, int H){
    	if(d == (1<<(k-1))){
    		rk[c[2*d-1]] = p[1];
    		int hh = 0;
    		for(int i = 1 ; i <= (1<<k-1) ; ++i) hh = (hh + 1ll*i*qsm(A,rk[i])%M) % M;
    		if(mp.count(hh) == 0) mp[hh] = 1;
    		rk[c[2*d-1]] = p[2];
    		hh = 0;
    		for(int i = 1 ; i <= (1<<k-1) ; ++i) hh = (hh + 1ll*i*qsm(A,rk[i])%M) % M;
    		if(mp.count(hh) == 0) mp[hh] = 1;
    		return;
    	}
    	
    	++tot;
    	int pos = tot;
    	c[pos] = c[2*d-1];
    	int r = get_r(d);
    	rk[c[2*d]] = r != -1 ? p[r+3] : 3;
    	dfs1(d+1, (H + a[c[2*d]][r+3]) % M);
    	rk[c[2*d]] = 0;
    	c[pos] = c[2*d];
    	rk[c[2*d-1]] = r != -1 ? p[r+3] : 3;
    	dfs1(d+1, (H + a[c[2*d-1]][r+3]) % M);
    	rk[c[2*d-1]] = 0;
    	--tot;
    }
    
    void dfs2(int d, int H){
    	if(flag) return;
    	if(d == (1<<(k-1))){
    		rk[c[2*d-1]] = p[1];
    		int hh = 0;
    		for(int i = 1 ; i <= (1<<k-1) ; ++i) hh = (hh + 1ll*(i+(1<<k-1))*qsm(A,rk[(i+(1<<k-1))])%M) % M;
    
    		if(mp.count(((h-hh)%M+M)%M) != 0) {
    			f1 = ((h-hh)%M+M)%M, f2 = hh;
    
    			flag = 1; return;
    		}
    		rk[c[2*d-1]] = p[2];
    		hh = 0;
    		for(int i = 1 ; i <= (1<<k-1) ; ++i) hh = (hh + 1ll*(i+(1<<k-1))*qsm(A,rk[(i+(1<<k-1))])%M) % M;
    
    		if(mp.count(((h-hh)%M+M)%M) != 0) {
    			f1 = ((h-hh)%M+M)%M, f2 = hh;
    			flag = 1; return;
    		}
    		return;
    	}
    	
    	++tot;
    	int pos = tot;
    	c[pos] = c[2*d-1];
    	int r = get_r(d);
    	rk[c[2*d]] = r != -1 ? p[r+3] : 3;
    	dfs2(d+1, (H + a[c[2*d]][r+3]) % M);
    	rk[c[2*d]] = 0;
    	c[pos] = c[2*d];
    	rk[c[2*d-1]] = r != -1 ? p[r+3] : 3;
    	dfs2(d+1, (H + a[c[2*d-1]][r+3]) % M);
    	rk[c[2*d-1]] = 0;
    	--tot;
    }
    
    void find1(int d, int H){
    	if(t1) return;
    	if(d == (1<<(k-1))){
    		rk[c[2*d-1]] = p[1];
    		int hh = 0;
    		for(int i = 1 ; i <= (1<<k-1) ; ++i) hh = (hh + 1ll*i*qsm(A,rk[i])%M) % M;
    		if(hh == f1){
    			t1 = 1;
    			for(int i = 1 ; i <= (1<<k-1) ; ++i) printf("%d ", rk[i]);
    			return;
    		}
    		rk[c[2*d-1]] = p[2];
    		hh = 0;
    		for(int i = 1 ; i <= (1<<k-1) ; ++i) hh = (hh + 1ll*i*qsm(A,rk[i])%M) % M;
    		if(hh == f1){
    			t1 = 1;
    			for(int i = 1 ; i <= (1<<k-1) ; ++i) printf("%d ", rk[i]);
    			return;
    		}
    		return;
    	}
    	
    	++tot;
    	int pos = tot;
    	c[pos] = c[2*d-1];
    	int r = get_r(d);
    	rk[c[2*d]] = r != -1 ? p[r+3] : 3;
    	find1(d+1, (H + a[c[2*d]][r+3]) % M);
    	rk[c[2*d]] = 0;
    	c[pos] = c[2*d];
    	rk[c[2*d-1]] = r != -1 ? p[r+3] : 3;
    	find1(d+1, (H + a[c[2*d-1]][r+3]) % M);
    	rk[c[2*d-1]] = 0;
    	--tot;
    }
    
    void find2(int d, int H){
    	if(t2) return;
    	if(d == (1<<(k-1))){
    		rk[c[2*d-1]] = p[1];
    		int hh = 0;
    		for(int i = 1 ; i <= (1<<k-1) ; ++i) hh = (hh + 1ll*(i+(1<<k-1))*qsm(A,rk[(i+(1<<k-1))])%M) % M;
    		if(hh == f2){
    			t2 = 1;
    			for(int i = 1 ; i <= (1<<k-1) ; ++i) printf("%d ", rk[i+(1<<k-1)]);
    			return;
    		}
    		rk[c[2*d-1]] = p[2];
    		hh = 0;
    		for(int i = 1 ; i <= (1<<k-1) ; ++i) hh = (hh + 1ll*(i+(1<<k-1))*qsm(A,rk[(i+(1<<k-1))])%M) % M;
    
    		if(hh == f2){
    			t2 = 1;
    			for(int i = 1 ; i <= (1<<k-1) ; ++i) printf("%d ", rk[i+(1<<k-1)]);
    			return;
    		}
    		return;
    	}
    	
    	++tot;
    	int pos = tot;
    	c[pos] = c[2*d-1];
    	int r = get_r(d);
    	rk[c[2*d]] = r != -1 ? p[r+3] : 3;
    	find2(d+1, (H + a[c[2*d]][r+3]) % M);
    	rk[c[2*d]] = 0;
    	c[pos] = c[2*d];
    	rk[c[2*d-1]] = r != -1 ? p[r+3] : 3;
    	find2(d+1, (H + a[c[2*d-1]][r+3]) % M);
    	rk[c[2*d-1]] = 0;
    	--tot;
    }
    
    void print(){
    	t1 = 0, t2 = 0;
    	tot = (1<<(k-1));
    	for(int i = 1 ; i <= tot ; ++i) c[i] = i;
    	find1(1, 0);
    	
    	for(int i = 1 ; i <= tot ; ++i) c[i] = i+tot;
    	find2(1, 0);
    }
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	flag = 0;
    	memset(rk, 0, sizeof(rk));
    	k = read(), A = read(), h = read();
    	
    	p[1] = 1, p[2] = 2, p[3] = 3, p[4] = 5, p[5] = 9, p[6] = 17;
    	for(int i = 1 ; i <= (1<<k) ; ++i){
    		for(int j = 1 ; j <= 6 ; ++j){
    			a[i][j] = 1ll * i * qsm(A, p[j]) % M;
    		}
    	}
    	
    	n = (1<<k);
    
    	tot = (1<<(k-1));
    	for(int i = 1 ; i <= tot ; ++i) c[i] = i;
    	dfs1(1, 0);
    
    	for(int i = 1 ; i <= tot ; ++i) c[i] = i+tot;
    	dfs2(1, 0);
    	
    	if(!flag) printf("-1
    ");
    	else print();
    
    	return 0;
    }
    
  • 相关阅读:
    English Sentenses【no use】
    MacOS显示和不显示隐藏文件
    各个会议期刊论文录取情况
    C++之linux下文件结构实现
    Ubuntu安装opencv
    tmux使用
    事件的默认行为 与 事件流
    currentTarget 与 Target 的区别
    元数据标签Embed
    fl,flash,mx包的区别
  • 原文地址:https://www.cnblogs.com/tuchen/p/15255233.html
Copyright © 2011-2022 走看看