专栏文章

题解:CF1767D Playoff

CF1767D题解参与者 1已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mir2u57t
此快照首次捕获于
2025/12/04 14:50
3 个月前
此快照最后确认于
2025/12/04 14:50
3 个月前
查看原文

启发式打表题解看这里

首先,我们根据题意写一个暴力程序,用于打表。考虑到 next_permutation() 函数在此时会导致程序统计大量的重复答案,当 nn 超过 44 时就无法在可以忍受时间内算出所有答案,我们采用 random_shuffle() 这个随机打乱函数,这样效率就大大提升啦!具体代码实现如下:
CPP
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[300005]; //大于2^18即可 
set<int> st; //一个用于去重的set 
int main(){
	int n;
	string s;
	cin>>n>>s;
	int m=1<<n;
	for(int i=1;i<=m;i++) a[i]=i; //创造初始排列 
	do{
		random_shuffle(a+1,a+1+m); //随机打乱一下 
		vector<int> v,tem;
		for(int i=1;i<=m;i++) v.push_back(a[i]);
		for(int i=0;i<n;i++){
			int sz=v.size();
			for(int j=0;j<sz;j+=2){
				if(s[i]=='1') tem.push_back(max(v[j],v[j+1]));
				else tem.push_back(min(v[j],v[j+1]));
			}
			v=tem;
			tem.clear();
		}//暴力统计此时的最终能力值 
		if(st.count(v[0])==0) cout<<v[0]<<" "; //将可能的答案输出 
		st.insert(v[0]);
	}while(1);//死循环,一直找
	return 0;
}
n=3n=3 时,最终打表结果:
s=s=结果
00000011
0010012,3,4,52,3,4,5
0100102,3,4,52,3,4,5
1001002,3,4,52,3,4,5
1101104,5,6,74,5,6,7
1011014,5,6,74,5,6,7
0110114,5,6,74,5,6,7
11111188
初步发现,结果与 0011 的位置无关,仅与 0011 的数目有关。
n=4n=4 时,最终打表结果:
ss 里面几个 11结果
0011
112,3,4,5,6,7,8,92,3,4,5,6,7,8,9
224,5,6,7,8,9,10,11,12,134,5,6,7,8,9,10,11,12,13
338,9,10,11,12,13,14,158,9,10,11,12,13,14,15
441616
首先观察到,设 ss 里面 11 的个数为 cntcnt,则结果的第一个数永远是 2cnt2^{cnt}
然后,我们不难发现结果具有严格的对称性,即从上到下增加的数的个数和从下到上对称位置增加的数的个数是相同的,由此可以推算出最后一个数为 2n2ncnt+12^n-2^{n-cnt}+1
最终结果仅需输出这两个边界之间的数即可,具体实现参考下方代码:
CPP
#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	string s;
	cin>>n>>s;
	int cnt=0;
	for(int i=0;i<n;i++) if(s[i]=='1') cnt++;
	int l=(1<<cnt);//左边界 
	cnt=n-cnt;
	int r=(1<<n)-(1<<cnt)+1; //右边界 
	for(int i=l;i<=r;i++) cout<<i<<" ";
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...