求为我的单 log 做法谋前途
查看原帖
求为我的单 log 做法谋前途
416975
sbno333楼主2024/11/22 15:54

做法简述:在从 11nn 枚举每个前缀确定时,考虑每个节点维护可能答案编号和,初始化时平凡的,记录可能的自由选手组成的胜者编号最小的。

对于编号和,由于我们只关心最终答案,这个不一定表示节点位置的编号和,而表示有用的编号和,对于胜者确定的点,这个编号和为当前节点真实的,否则不一定真实,但一定为到后面不会被因为能力值卡掉的点,每个点预处理哪里被卡掉。然后暴力从叶子向跟转移,每次转移有三种情况,两个儿子都确定(平凡),一个确定(如果必须用那个儿子就平凡,否则考虑那个儿子之后是否会因为能力值卡掉,然后是否添加,右边肯定添加),或者都没确定,直接加和即可。

代码:

#include<bits/stdc++.h>
using namespace std;

int gg;
int aa[100009];
int c[100009];
int n,m;
int k;
bool d[21][200009];
int a[100009];
int x[4];
long long ans[100009];
int hz[21][200009];
long long sm[21][200009];
bool ok[100009][21];
inline void inite(){
	cin>>x[0]>>x[1]>>x[2]>>x[3];
	for(int i=1;i<=n;i++){
		a[i]=(aa[i]^x[i%4]);
		ans[i-1]=0;
	}
	int k;
	k=0;
	while((1ll<<k)<n){
		k++;
	}
	for(int i=0;i<=k;i++){
		for(int j=0;j<=n;j++){
			ok[j][i]=0;
		}
	}
	for(int i=0;i<=k;i++){
		for(int j=0;j<(1<<(k-i));j++){
			if(!i){
				sm[i][j]=j+1;hz[i][j]=j;
			}else{
				sm[i][j]=sm[i-1][j<<1]+sm[i-1][j<<1|1];hz[i][j]=hz[i-1][j<<1];	
			}
		}
	}
}
inline void prk(){
	long long anss;
	anss=0;
	for(int i=1;i<=m;i++){
		anss^=(ans[c[i]]*i);
	}
	cout<<anss<<endl;
}
inline void sc(int x,int y){
	int l,r;
	l=(y<<1);
	r=((y<<1)|1);
	if(hz[x-1][l]==-1&&hz[x-1][r]==-1){
		hz[x][y]=-1;
		if(d[x][y]){
			if(ok[sm[x-1][r]][x]){
				sm[x][y]=sm[x-1][r];
			}else{
				sm[x][y]=sm[x-1][l];
			}
		}else{
			if(ok[sm[x-1][l]][x]){
				sm[x][y]=sm[x-1][l];
			}else{
				sm[x][y]=sm[x-1][r];
			}
		}
		return; 
	}
	if(hz[x-1][l]==-1){
		sm[x][y]=0;
		if(d[x][y]){
			hz[x][y]=hz[x-1][r];
			sm[x][y]+=sm[x-1][r];
			if(ok[sm[x-1][l]][gg]){
				sm[x][y]+=sm[x-1][l];
			}
		}else{
			if(!ok[sm[x-1][l]][x]){
				hz[x][y]=hz[x-1][r];
				sm[x][y]+=sm[x-1][r];
			}else{
				sm[x][y]+=sm[x-1][l];
				hz[x][y]=-1;
			}
		}
		return; 
	}
	sm[x][y]=0;
	hz[x][y]=hz[x-1][l];
	sm[x][y]+=sm[x-1][r]+sm[x-1][l];
}
inline void _main(){
	inite();
	int k;
	k=0;
	while((1<<k)<n){
		k++;
	}
	gg=0;
	for(int i=0;i<n;i++){
		int z;
		z=i;
		ok[i+1][0]=0;
		for(int j=1;j<=k;j++){
			bool g;
			g=(z&1);
			z>>=1;
			if(g==d[j][z]&&a[i+1]<j){
				ok[i+1][j]=0;
				break;
			}else{
				ok[i+1][j]=1;
			}
		}
	}
	for(int i=1;i<=n;i++){
		while((1<<gg)<i){
			gg++;
		}
		//cout<<i<<"-"<<gg<<endl;
		int z;
		z=i-1;
		int g;
		g=0;
		sm[g][z]=i;
		hz[g][z]=-1;
		while(z){
			z>>=1;
			g++;
			sc(g,z);
		}
		//cout<<sm[gg][0]<<endl;
		ans[i]=sm[gg][0];
	}
	prk();
}
signed main(){
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>aa[i];
	}
	for(int i=1;i<=m;i++){
		cin>>c[i];
	}
	int k;
	k=0;
	while((1<<k)<n){
		k++;
	}
	for(int c=1;c<=k;c++){
		for(int j=0;j<(1<<(k-c));j++){
			char t;
			cin>>t;
			d[c][j]=t-'0';
		}
	}
	int t;
	cin>>t;
	while(t--){
		_main();
	}
	return 0;
}

80 分,我要给它完整的一生。

2024/11/22 15:54
加载中...