[集训队作业2018]uoj 425 strings - 搜索 - bitset

这题……
题解:
考虑 O ( 2 n ) O(2^n) 暴力枚举答案,可以分成两段,先枚举前 a a 位,然后算出目前匹配那些串,设为S。对每个给定的串 s t r i str_i 求其能匹配后面枚举出来的 2 n a 2^{n-a} 个串中的哪些串,假设叫 b i b_i ,那么前a位后面能接上的就是S中的串 s t r str 对应的 b b 的并。
因此对 { 1 ,   , q } \{1,\cdots,q\} 的所有子集求b的并集,可以预处理的时候分块,这样就会发现那个 2 n q / 32 2^nq/32 的部分可以出掉一个常数。通过优秀的调参可以过掉本题。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int BS=(1<<15)+1,QC=11,QS=(1<<10)+10,N=33,Q=110;
bitset<BS> rb[QC][QS],ans;char s[Q][N];int L[QC],R[QC];
inline int ok(char *s,int v,int n)
{
	rep(i,0,n-1) if(s[i]!='?'&&s[i]-'0'!=((v>>i)&1)) return 0;return 1;
}
int main()
{
//	freopen("data.in","r",stdin);
	int n=inn(),q=inn();
	rep(i,1,q) scanf("%s",s[i]);
	int a=min(n,15),b=n-a,qs=10,qc=(q-1)/qs+1;
//	debug(a)sp,debug(b)sp,debug(qs)sp,debug(qc)ln;
	rep(i,1,qc)
	{
		L[i]=(i-1)*qs+1,R[i]=min(i*qs,q);
		rep(j,L[i],R[i]) rep(k,0,(1<<b)-1)
			if(ok(s[j]+a,k,b)) rb[i][1<<(j-L[i])].set(k);
		rep(j,1,(1<<(R[i]-L[i]+1))-1)
		{
			int k=j&(-j);if(j==k) continue;
			rb[i][j]=rb[i][j^k]|rb[i][k];
		}
	}
	int Ans=0;
	rep(i,0,(1<<a)-1)
	{
		ans.reset();
		rep(j,1,qc)
		{
			int t=0;
			rep(k,L[j],R[j]) if(ok(s[k],i,a)) t|=1<<(k-L[j]);
			ans|=rb[j][t];
		}
		Ans+=ans.count();
	}
	return !printf("%d\n",Ans);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/88086740