P12494 题解
DaiRuiChen007 · · 题解
Problem Link
题目大意
给定
s_1\sim s_{n-1} ,其中每个元素都是\mathrm{AND},\mathrm{OR},\oplus 三种运算符之一,q 次询问m 。求有多少
c_1\sim c_n\in [0,2^k) 并且存在a_1\sim a_n 满足a_i\in[0,c_i] 且((a_1 \otimes_{s_1}a_2)\otimes_{s_2}a_3\cdots)\otimes_{s_{n-1}}a_n=m 。答案对
2^{32} 取模。数据范围:
n,q\le 1000,k\le 30 。
思路分析
考虑如何检验一组
打表发现能表示出的
那么我们只要考虑操作为
但是正着依然不好维护判定过程考虑再倒过来,此时我们只要贪心让要得出的
-
-
因此只要 $x'\operatorname{OR}c\ge x$ 即可,从高到低考虑,如果这一位上 $c=0$ 则不更新,如果这一位 $c=1,x=1$ 则 $x$ 这一位变成 $0$,否则低位全部清空。 更具体一点,我们找到 $x$ 不包含的一个位 $2^p$,然后把低 $p$ 位清零,系数 $2^p$($c$ 的低位填法),然后每个 $>p$ 的位上的 $1$ 可以选择是否变成 $0$。
那么对这个过程 dp,但这次从前往后 dp。
对于
可以把
因此对于每个
那么我们从前往后,会确定若干个位置必定属于
然后考虑对
并且在这个位置,我们具体选择哪个
那么动态维护从前往后
对于每个位,考虑他从前往后首次被钦定为
注意到转移系数大部分都是
考虑这样刻画轮廓线:
容易发现系数一定是
查询答案的时候暴力枚举每个合法的状态即可。
时间复杂度
代码呈现
#include<bits/stdc++.h>
#define ui unsigned
#define ull unsigned long long
using namespace std;
const int MAXN=1005,MAXM=72005,MAXE=2e6+5;
typedef array<int,32> info;
int n,k,m,q,op[MAXN],lo[MAXM],vl[MAXM][32];
info st[MAXM],s;
mt19937_64 rnd(time(0));
ull wt[32],hs[MAXM];
const int P=1e7+19;
int hd[P],nxt[MAXM],msk[MAXM];
int qry(ull x) {
for(int i=hd[x%P];i;i=nxt[i]) if(hs[i]==x) return i;
return 0;
}
void dfs(int i,int c) {
if(i>k) {
++s[k],st[++m]=s;
for(int j=0;j<=k;++j) hs[m]+=s[j]*wt[j];
nxt[m]=hd[hs[m]%P],hd[hs[m]%P]=m,--s[k];
return ;
}
for(s[i]=0;s[i]*i<=c;++s[i]) dfs(i+1,c-i*s[i]);
}
int to[MAXM][2],R[MAXE],Z[MAXE],e,h[MAXM];
ui pr[MAXM][2],f[MAXM],g[MAXM];
signed main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>k>>q;
for(int i=0;i<=k;++i) wt[i]=rnd();
s.fill(0),dfs(1,31),s.fill(0),s[0]=1,dfs(1,31);
for(int i=2;i<=n;++i) { char c; cin>>c,op[i]=(c!='A'); }
for(int i=1;i<=m;++i) {
int &p=lo[i]=0;
for(;!st[i][p];++p);
to[i][1]=qry(p?hs[i]+wt[p]:hs[i]),pr[i][1]=1u<<p;
to[i][0]=i,pr[i][0]=1u<<k;
for(int j=0;j<k;++j) {
if(st[i][j]) pr[i][0]-=1u<<j,msk[i]|=1<<j;
else R[++e]=qry(hs[i]+wt[j]),Z[e]=j;
}
h[i]=e;
for(int j=k;~j;--j) vl[i][j]=vl[i][j+1]+max(0,st[i][j]-1);
}
f[qry(wt[k])]=1;
int ct=0;
for(int o=1;o<=n;++o) {
memset(g,0,sizeof(g)),ct+=op[o];
for(int i=1;i<=m;++i) if(f[i]) {
g[to[i][op[o]]]+=f[i]*pr[i][op[o]];
if(!op[o]) for(int j=h[i-1]+1;j<=h[i];++j) {
if(Z[j]<lo[i]) g[R[j]]-=f[i]<<Z[j];
else g[R[j]]-=f[i]*(ct-vl[i][Z[j]]+1)<<Z[j];
}
}
memcpy(f,g,sizeof(f));
}
for(int x;q--;) {
cin>>x; ui z=0;
for(int i=1;i<=m;++i) if((x|msk[i])==x) {
ui t=f[i];
for(int j=0;j<k;++j) if((x>>j&1)&&!st[i][j]) t*=ct-vl[i][j]+1;
z+=t;
}
cout<<z<<"\n";
}
return 0;
}