【CF582E】Boolean Function 树形DP+FWT
【CF582E】Boolean Function
题意:给你一个长度为n的表达式,其中未知数有A,B,C,D和?,运算有&和|和?(表达式中用括号确定了唯一的运算顺序)。?代表A,B,C,D或&,|。A,B,C,D的值是0或1。再给你m个条件$a,b,c,d,e$,代表A,B,C,D分别等于a,b,c,d时表达式的值为e。求有多少种将?填满的方式,符合给出的所有条件?
$n\le 500,m\le 2^4$
题解:CF总考这种用二进制表示特殊状态的题,感觉十分考验人类的抽象能力。
因为变量的可能情况的只有$2^4$种,所以我们用一个4位的二进制字符表示。这样一来我们就可以发现可能的表达式只有$2^{2^4}$种,所以我们再用一个16位的二进制来表示一个表达式(不要晕)。这个二进制数的第i位为0/1的意义是:如果把i用二进制表示,则i的每一位代表每个变量的取值。在这些变量分别取这些值时,这个表达式的值为0/1(千万不要晕)。
因为表达式是一堆括号围出来的,我们可以将括号的嵌套看成一个树形结构,并且是一棵二叉树。我们设f[x][S]表示对于当前节点对应的子树,有多少种方法使得得到的表达式为S。转移时我们通过左右儿子的f以及当前节点的运算符即能确定当前节点的f值。然后你会发现转移的实质就是FWT。。。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int P=1000000007;
char str[510];
int n,m,tot;
int f[170][(1<<16)+4],g[(1<<16)+4],p1[20],p2[20];
inline void add(int &x,int y) {x+=y; if(x>=P) x-=P;}
inline void dec(int &x,int y) {x-=y; if(x<=0) x+=P;}
inline void fwt1(int *a)
{
for(int h=0;h<16;h++) for(int i=0;i<(1<<16);i++) if((i>>h)&1) add(a[i],a[i^(1<<h)]);
}
inline void ufwt1(int *a)
{
for(int h=0;h<16;h++) for(int i=0;i<(1<<16);i++) if((i>>h)&1) dec(a[i],a[i^(1<<h)]);
}
inline void fwt0(int *a)
{
for(int h=0;h<16;h++) for(int i=0;i<(1<<16);i++) if(!((i>>h)&1)) add(a[i],a[i|(1<<h)]);
}
inline void ufwt0(int *a)
{
for(int h=0;h<16;h++) for(int i=0;i<(1<<16);i++) if(!((i>>h)&1)) dec(a[i],a[i|(1<<h)]);
}
int build(int l,int r)
{
int x=++tot;
if(l==r)
{
int i,j,S;
for(j=0;j<4;j++)
{
if(str[l]=='?'||str[l]=='A'+j)
{
for(S=i=0;i<16;i++) if((i>>j)&1) S|=1<<i;
f[x][S]++;
}
if(str[l]=='?'||str[l]=='a'+j)
{
for(S=i=0;i<16;i++) if(!((i>>j)&1)) S|=1<<i;
f[x][S]++;
}
}
return x;
}
int i,mid,t=0;
for(i=l;i<=r;i++)
{
t+=(str[i]=='(')-(str[i]==')');
if(!t) break;
}
mid=i+1;
int ls=build(l+1,mid-2),rs=build(mid+2,r-1);
if(str[mid]=='|')
{
fwt1(f[ls]),fwt1(f[rs]);
for(i=0;i<(1<<16);i++) f[x][i]=1ll*f[ls][i]*f[rs][i]%P;
ufwt1(f[x]);
}
else if(str[mid]=='&')
{
fwt0(f[ls]),fwt0(f[rs]);
for(i=0;i<(1<<16);i++) f[x][i]=1ll*f[ls][i]*f[rs][i]%P;
ufwt0(f[x]);
}
else
{
fwt0(f[ls]),fwt0(f[rs]);
for(i=0;i<(1<<16);i++) g[i]=1ll*f[ls][i]*f[rs][i]%P;
ufwt0(g),ufwt0(f[ls]),ufwt0(f[rs]);
memcpy(f[x],g,sizeof(g));
fwt1(f[ls]),fwt1(f[rs]);
for(i=0;i<(1<<16);i++) g[i]=1ll*f[ls][i]*f[rs][i]%P;
ufwt1(g);
for(i=0;i<(1<<16);i++) add(f[x][i],g[i]);
}
return x;
}
int main()
{
scanf("%s%d",str+1,&m),n=strlen(str+1);
int i,j,ans=0,S=0,t;
for(i=1;i<=m;i++)
{
for(S=j=0;j<4;j++) scanf("%d",&t),S|=t<<j;
scanf("%d",&t),p1[i]=S,p2[i]=t;
}
build(1,n);
for(i=0;i<(1<<16);i++)
{
for(j=1;j<=m;j++) if(((i>>p1[j])&1)!=p2[j]) break;
if(j>m) add(ans,f[1][i]);
}
printf("%d",ans);
return 0;
}
【CF582E】Boolean Function 树形DP+FWT的更多相关文章
- CF582E Boolean Function(DP,状态压缩,FMT)
简单题. 我第二道自己做出来的 2900 没毛病,我没切过 2800 的题 lqy:"CF 评分 2800 是中等难度" 我活个啥劲啊 为了方便(同时压缩状态个数),先建出表达式树 ...
- HDU5909 Tree Cutting(树形DP + FWT)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5909 Description Byteasar has a tree T with n ve ...
- hdu 5909 Tree Cutting [树形DP fwt]
hdu 5909 Tree Cutting 题意:一颗无根树,每个点有权值,连通子树的权值为异或和,求异或和为[0,m)的方案数 \(f[i][j]\)表示子树i中经过i的连通子树异或和为j的方案数 ...
- HDU - 5909 Tree Cutting (树形dp+FWT优化)
题意:树上每个节点有权值,定义一棵树的权值为所有节点权值异或的值.求一棵树中,连通子树值为[0,m)的个数. 分析: 设\(dp[i][j]\)为根为i,值为j的子树的个数. 则\(dp[i][j\o ...
- HDU.5909.Tree Cutting(树形DP FWT/点分治)
题目链接 \(Description\) 给定一棵树,每个点有权值,在\([0,m-1]\)之间.求异或和为\(0,1,...,m-1\)的非空连通块各有多少个. \(n\leq 1000,m\leq ...
- hdu5909 Tree Cutting 【树形dp + FWT】
题目链接 hdu5909 题解 设\(f[i][j]\)表示以\(i\)为根的子树,\(i\)一定取,剩余节点必须联通,异或和为\(j\)的方案数 初始化\(f[i][val[i]] = 1\) 枚举 ...
- [cf582E]Boolean Function
由于每一个运算都有括号,因此添加的运算不会改变运算顺序 先将其建出一棵表达式树,也就是维护两个栈,是节点和运算符优先级单调递增的栈(设置左括号优先级最低,右括号弹出直至左括号) 每一次运算,也就是新建 ...
- HDU 5977 Garden of Eden (树形dp+快速沃尔什变换FWT)
CGZ大佬提醒我,我要是再不更博客可就连一月一更的频率也没有了... emmm,正好做了一道有点意思的题,就拿出来充数吧=.= 题意 一棵树,有 $ n (n\leq50000) $ 个节点,每个点都 ...
- fwt优化+树形DP HDU 5909
//fwt优化+树形DP HDU 5909 //见官方题解 // BestCoder Round #88 http://bestcoder.hdu.edu.cn/ #include <bits/ ...
随机推荐
- Java Comparator字符排序(数字、字母、中文混合排序)
Java.lang.Character类 复习一下 这是修正前的排序效果: 这是修正后的排序效果: 完整示例: 以下是排序的部份代码(非全部代码:拼音首字母算法不在其中) import java.ut ...
- Windows 下的 Makefile 编写
Windows 下的 Makefile 编写(一)Makefile的基本规则 作者:cntrump Makefile对于很多人来说是陌生的,特别是习惯于使用 IDE 的人来说,似乎没有听说过 Make ...
- 子级div相对于父级div位置不变
设置父级div为相对位置 设置子级div为绝对位置 代码如下: <!DOCTYPE html> <html> <head> <meta charset=&qu ...
- 详细解读Android中的搜索框(三)—— SearchView
本篇讲的是如何用searchView实现搜索框,其实原理和之前的没啥差别,也算是个复习吧. 一.Manifest.xml 这里我用一个activity进行信息的输入和展示,配置方式还是老样子,写一个输 ...
- C#获取网页的HTML码、下载网站图片 get post
/// <summary> /// 获取网页的HTML码 /// </summary> /// <param name="url">链接地址&l ...
- 【Java】数组不能通过toString方法转为字符串
java里,所有的类,不管是java库里面的类,或者是你自己创建的类,全部是从object这个类继承的.object里有一个方法就是toString(),那么所有的类创建的时候,都有一个toStrin ...
- 转移 Visual Studio 2017 的安装临时文件
每次更新 Visual Studio 2017 会在 C 盘留下大量的缓存文件,因为目录比较深,怕以后忘了,用目录链接的形式转移到其它磁盘,也好方便清理: mklink /D C:\ProgramDa ...
- [转]关于ios 推送功能的终极解决
刚刚做了一个使用推送功能的应用 遇到了一些问题整的很郁闷 搞了两天总算是弄明白了 特此分享给大家 本帖 主要是针对产品发布版本的一些问题 综合了网上一些资料根据自己实践写的 不过测试也可以看看 首先要 ...
- 使用vw做移动端页面的适配
Flexible到今天也有几年的历史了,解救了很多同学针对于H5页面布局的适配问题.而这套方案也相对而言是一个较为成熟的方案.简单的回忆一下,当初为了能让页面更好的适配各种不同的终端,通过Hack手段 ...
- Summary Checklist for Run-Time Kubernetes Security
Here is a convenient checklist summary of the security protections to review for securing Kubernetes ...