玄关求调(附带注释)
查看原帖
玄关求调(附带注释)
341091
End_Sunset楼主2025/8/1 19:59

实现方法为枚举。先枚举替换串,再把替换串逐个插入,详见注释

#include<bits/stdc++.h>
using namespace std;
#define pb push_back() 
const int N=2e6+5;
int L,Q;
string s;
long long pre[N],suf[N],md[N],val[N],f[N]; 

int main(){
	cin>>L>>Q;
	cin>>s; int n=s.length();
	for(int i=0; i<n; i++)
		pre[i]=suf[i]=f[i]=s[i]-'0';
	for(int i=0; i<L; i++){//按维求和
		for(int j=0; j<n; j++)
			if((j>>i)&1) pre[j]+=pre[j^(1<<i)]; //高维前缀和 
		for(int j=n-1; j>=0; j--)
			if(!((j>>i)&1)) suf[j]+=suf[j^(1<<i)];//高维后缀和	
	}
	for(int i=1; i<=Q; i++){
		string T; cin>>T;
		int a=0,b=0,c=0,A=0,B=0; long long ans=0;
		for(int j=0; j<L; j++) {
			if(T[L-j-1]=='?') md[j]=2,a++,A+=(1<<j);
			if(T[L-j-1]=='1') md[j]=1,b++,B+=(1<<j);
			if(T[L-j-1]=='0') md[j]=0,c++;
		}
		if(a<=b&&a<=c){  //枚举? 
			for(int j=0; j<(1<<a); j++){//枚举填充的数
				int Snk=B;//待填充数
				for(int k=0,p=0; k<a; k++){//填充
					while(p<=L-1&&md[p]!=2) p++;//不填?以外的空
					if(p==L) break;
					long long op=(j>>k)&1;
					Snk+=op*(1<<p); 
				}
				ans+=f[Snk]; 
			}
		}
		else if(b<=c&&b<=a){  //将1容斥为?-0
			for(int j=0; j<(1<<b); j++){ // 1=? 0=0 
				int Snk=A,d=0;//d为容斥系数
				for(int k=0; k<b; k++) d+=(((j>>k)&1)^1);
				for(int k=0,p=0; k<b; k++){
					while(p<=L-1&&md[p]!=1) p++;
					if(p==L) break;
					long long op=(j>>k)&1;
					Snk+=op*(1<<p);
				}  
				ans+=((d&1) ? -1ll : 1ll)*pre[Snk];
		//		cout<<((d&1) ? -1 : 1)<<" "<<Snk<<"\n";
			}
		}
		else{ //将0容斥为?-1
			for(int j=0; j<(1<<c); j++){ //1=1 0=?
				int Snk=B,d=0;
				for(int k=0; k<c; k++) d+=((j>>k)&1);
				for(int k=0,p=0; k<c; k++){
					while(p<=L-1&&md[p]!=0) p++;
					if(p==L) break;
					long long op=(j>>k)&1;
					Snk+=op*(1<<p);
				}
				ans+=((d&1) ? -1ll : 1ll)*suf[Snk];
			//	cout<<((d&1) ? -1 : 1)<<" "<<Snk<<"\n";
			}
		} 
		cout<<(ans>0 ? ans : -ans)<<"\n";
	}
}
2025/8/1 19:59
加载中...