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\n");
	else print();

	return 0;
}
上一篇:练习


下一篇:3.30_419.数组_二维数组及滚动数组_甲板上的战舰(middle)