题解:P16084 [ICPC 2024 NAC] Comparator
lailai0916 · · 题解
题意简述
一个比较函数依次执行若干规则。每条规则读取两个
统计函数对全部字的一元组、有序二元组和有序三元组中,分别违反以下条件的数量:
解题思路
最多有
每个表达式实际仅接收两个比特
于是,变量 x 对应掩码 y 对应 0 对应 1 对应
布尔运算可以一次作用于四种输入:与、或、异或直接使用对应的按位运算;非运算异或
使用数值栈和运算符栈求值。优先级必须按题面设置为 !、=、&、|、^ 依次降低,不能使用 C++ 自身的优先级。遇到二元运算符时,先计算栈顶优先级不低于它的运算符,从而实现二元运算的左结合;遇到前缀 ! 时直接入栈,使连续的非运算从内向外执行。左括号阻断栈顶运算,右括号将对应括号内的运算全部完成。
两个栈都显式存储,没有递归调用,能够处理长度接近
再压缩规则。固定第一、第二个字读取的位置 fst[a][b][t] 和 val[a][b][t] 中。每读入一条规则,检查其真值表的四位,仅填写尚未出现过的情况。
对于同一组
这里必须同时保留返回
枚举两个字
字从左到右按
设
第一项违例是
第二项违例要求 G[u]&H[u] 中的置位数即可。题目统计有序对,
第三项违例要求 G[v]&~G[u] 的置位数。每个有序三元组会在它对应的
位集按最大规模分配,多余位置始终没有出现在任何
设所有表达式的总长度为 int。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=1029;
const int M=1000005;
const int K=15;
const int inf=0x3f3f3f3f;
int top,cnt;
int stk[M],pr[128],fst[K][K][4];
bool val[K][K][4];
char op[M];
bitset<N> G[N],H[N];
void calc()
{
cnt--;
char c=op[cnt];
if(c=='!'){stk[top-1]^=15;return;}
top--;
int y=stk[top];
if(c=='=')stk[top-1]^=y^15;
else if(c=='&')stk[top-1]&=y;
else if(c=='|')stk[top-1]|=y;
else if(c=='^')stk[top-1]^=y;
}
int parse(const string &s)
{
top=cnt=0;
for(auto c:s)
{
if(c=='x')stk[top++]=12;
else if(c=='y')stk[top++]=10;
else if(c=='0')stk[top++]=0;
else if(c=='1')stk[top++]=15;
else if(c=='('||c=='!')op[cnt++]=c;
else if(c==')')
{
while(op[cnt-1]!='(')calc();
cnt--;
}
else
{
while(cnt&&op[cnt-1]!='('&&pr[op[cnt-1]]>=pr[c])calc();
op[cnt++]=c;
}
}
while(cnt)calc();
return stk[0];
}
bool cmp(int x,int y,int k,bool res)
{
int pos=inf;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=k;j++)
{
int t=((x>>(k-i))&1)*2+((y>>(k-j))&1);
if(fst[i][j][t]>=pos)continue;
pos=fst[i][j][t];
res=val[i][j][t];
}
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
pr['!']=5;
pr['=']=4;
pr['&']=3;
pr['|']=2;
pr['^']=1;
memset(fst,0x3f,sizeof fst);
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
int a,b;
string s;
bool r;
cin>>a>>b>>s>>r;
int mask=parse(s);
for(int j=0;j<4;j++)
{
if(!(mask>>j&1)||fst[a][b][j]!=inf)continue;
fst[a][b][j]=i;
val[a][b][j]=r;
}
}
bool r;
cin>>r;
int m=1<<k;
for(int i=0;i<m;i++)
{
for(int j=0;j<m;j++)if(cmp(i,j,k,r))G[i][j]=H[j][i]=1;
}
int ans[3]={};
for(int i=0;i<m;i++)
{
ans[0]+=G[i][i];
ans[1]+=(G[i]&H[i]).count();
for(int j=0;j<m;j++)if(G[i][j])ans[2]+=(G[j]&~G[i]).count();
}
cout<<ans[0]<<' '<<ans[1]<<' '<<ans[2]<<'\n';
return 0;
}