https://www.zybuluo.com/ysner/note/1298755

题面

有一天小胡同学看到了一种表达式。这个表达式有四个变量\(A,B,C,D\)。这四

个变量都只有\(0\)和\(1\)两种取值。小写字母\(a,b,c,d\)表示对应变量取反后的值。

  • 如果\(X\)是个变量,那么\(X\)是个表达式。
  • 如果\(X,Y\)都是表达式,那么\((X)|(Y)\)是个表达式。
  • 如果\(X,Y\)都是表达式,那么\((X)\&(Y)\)是个表达式。

小胡同学正准备对一个表达式求值的时候,他发现邪恶的小王把这个表达式

的一些变量或运算符给抹掉了(所有的括号均没被抹掉),小胡同学想复原这个

表达式,他现在有\(m\)个已知的运算结果。每个运算结果记为\(f(A,B,C,D)=E\),

表示当\(A,B,C,D\)取对应值的时候整个表达式的结果为\(E\)。

现在小胡同学想知道,有多少个合法的表达式满足所有的运算结果。

  • \(60pts\ m\leq8\)
  • \(100pts\ |S|\leq500,m\leq16\)

解析

\(60pts\)算法

一般来说,求表达式的值都是用栈。

然而这样不能应用于\(DP\)。

所以有个东西叫表达式树

它的形态是,最底层是所有的数字,两个数字间的运算符作为它们共同的父亲,同时这个父亲代表它们的运算结果,依次类推。。。

设\(f[i][j]\)为在第\(i\)个结点,当前运算结果集合为\(j\)的方案数。

然后每次递归进左边的括号和右边的括号,最后合并左边和右边的答案即可。

(然而并没那么好写)

复杂度\(O(|S|2^{2m})\)。(然而其实|S|中大多数都是括号,运算符可能只有\(100+\)个)

要特别注意当前处理完后,到达下一次处理的字符要挪几位,有时\(1\)位,有时\(2\)位。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define re register
#define il inline
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=100,mod=1e9+7;
int n,m,st[6],S,p,tot,f[505][1<<17];
char s[550];
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void dfs(re int x)
{
re int ls,rs;
if(s[p]!='(')
{
if(s[p]=='?') fp(i,0,3) ++f[x][st[i]],++f[x][st[i]^S];
else if(s[p]>='A'&&s[p]<='D') ++f[x][st[s[p]-'A']];
else ++f[x][st[s[p]-'a']^S];
p+=2;//到运算符
return;
}
++p;dfs(ls=++tot);
char op=s[p];
if(op!='|'&&op!='&'&&op!='?') return;
p+=2;//到右边括号的内部
dfs(rs=++tot);
fp(i,0,S)
fp(j,0,S)
{
if(op!='|') (f[x][i&j]+=1ll*f[ls][i]*f[rs][j]%mod)%=mod;
if(op!='&') (f[x][i|j]+=1ll*f[ls][i]*f[rs][j]%mod)%=mod;
}
++p;//到达下一次运算
}
int main()
{
freopen("calculate.in","r",stdin);
freopen("calculate.out","w",stdout);
scanf("%s",s+1);n=strlen(s+1);m=gi();S=(1<<m)-1;
fp(i,1,m)
fp(j,0,4) (st[j]<<=1)|=gi();
dfs(tot=p=1);
printf("%d\n",f[1][st[4]]);
fclose(stdin);
fclose(stdout);
return 0;
}

\(100pts\)算法

\(FWT\)专门用于处理异或、或、与下标时的卷积运算。

通常复杂度为\(O(nlogn)\)。

这样搞一搞,复杂度就成\(O(|S|2^mm)\)了。

但是这玩意儿应用范围很小,先鸽着。

[noip模拟赛]算算数的更多相关文章

  1. noip模拟赛 算

    [问题背景]zhx 帮他妹子做数学题.[问题描述]求: 如 N=3, M=3, 这个值为 1^1+1^2+1^3+2^1+2^2+2^3+3^1+3^2+3^3=56. [输入格式]仅一行, 包含两个 ...

  2. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  3. CH Round #49 - Streaming #4 (NOIP模拟赛Day2)

    A.二叉树的的根 题目:http://www.contesthunter.org/contest/CH%20Round%20%2349%20-%20Streaming%20%234%20(NOIP 模 ...

  4. 【noip模拟赛5】细菌 状压dp

    [noip模拟赛5]细菌   描述 近期,农场出现了D(1<=D<=15)种细菌.John要从他的 N(1<=N<=1,000)头奶牛中尽可能多地选些产奶.但是如果选中的奶牛携 ...

  5. 10.16 NOIP模拟赛

    目录 2018.10.16 NOIP模拟赛 A 购物shop B 期望exp(DP 期望 按位计算) C 魔法迷宫maze(状压 暴力) 考试代码 C 2018.10.16 NOIP模拟赛 时间:2h ...

  6. NOIP模拟赛-2018.11.7

    NOIP模拟赛 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 编译之前另存一份,听说如果敲 ...

  7. Nescafe #29 NOIP模拟赛

    Nescafe #29 NOIP模拟赛 不知道这种题发出来算不算侵权...毕竟有的题在$bz$上是权限题,但是在$vijos$似乎又有原题...如果这算是侵权的话请联系我,我会尽快删除,谢谢~ 今天开 ...

  8. NOI.AC NOIP模拟赛 第五场 游记

    NOI.AC NOIP模拟赛 第五场 游记 count 题目大意: 长度为\(n+1(n\le10^5)\)的序列\(A\),其中的每个数都是不大于\(n\)的正整数,且\(n\)以内每个正整数至少出 ...

  9. 2016-06-19 NOIP模拟赛

          2016-06-19 NOIP模拟赛 by coolyangzc 共3道题目,时间3小时 题目名 高级打字机 不等数列 经营与开发 源文件 type.cpp/c/pas num.cpp/c ...

随机推荐

  1. c++基础_矩阵乘法

    #include <iostream> using namespace std; int main(){ int a,b; cin>>a>>b; long c[a] ...

  2. 字符串str.format()方法的个人整理

    引言: 字符串的内置方法大致有40来个,但是一些常用的其实就那么20几个,而且里面还有类似的用法,区分度高比如isalpha,isalnum,isdigit,还有一些无时不刻都会用到的split切分, ...

  3. LeetCode 122. Best Time to Buy and Sell Stock II (stock problem)

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  4. BUAA_OO_博客作业四

    BUAA_OO_博客作业四 1 第四单元两次作业的架构设计 1.1 第13次作业 类图 ​ 作业要求:通过实现UmlInteraction这个官方提供的接口,来实现自己的UmlInteraction解 ...

  5. xtu summer individual 5 A - To Add or Not to Add

    To Add or Not to Add Time Limit: 2000ms Memory Limit: 262144KB This problem will be judged on CodeFo ...

  6. c/c++ 位域的概念

    位域 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位.例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可.为了节省存储空间,并使处理简便,C语言又提供了一种数 ...

  7. SpringBoot入门系列~Spring-Data-JPA自动建表

    1.pom.xml引入Spring-Data-Jpa和mysql依赖 <!-- Spring-data-jpa依赖 --> <dependency> <groupId&g ...

  8. Linux下汇编语言学习笔记36 ---

    这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...

  9. JQuery判断radio是否选中并获取选中值的示例代码

    这篇文章主要介绍了JQuery判断radio是否选中并获取选中值的方法,代码很简单,但很实用,需要的朋友可以参考下 其他对radio操作功能,以后在添加.直接上代码,别忘记引用JQuery包 ? 1 ...

  10. hdu4696 Answers(循环节+找规律)

    题意: 分析: 容易想到先把T数组按位置和对应权值建一个有向图(类似置换群那种指法) 然后图建完了,如果C[]里面都是2,那显然只能凑出那些偶数,奇数是不能凑出来的 如果C[]有1有2呢? 事实上是可 ...