题目描述
给定一个只由0(假)、1(真)、&(逻辑与)、|(逻辑或)和^(异或)五种字符组成的字符串express,再给定一个布尔值desired。求出express能有多少种组合方式,可以达到desired的结果。并输出你所求出的总方案数对+7取模后的值。
输入描述
输出两行,第一行包含一个只有0、1、&、|和^组成的字符串。其长度小于500,第二行只有一个布尔值,代表desired。
输出描述
输出一个整数,表示取模后的答案。
Sample Input
1^0|0|1
false
Sample Output
2
1^((0|0)|1)和1^(0|(0|1))可以得到false
题目链接:表达式得到期望结果的组合种数__牛客网
外循环从左到右依次遍历逻辑运算符,假设第 i 个位置的运算符为最后一个运算的( i 位置左边整体和 i 位置右边整体先运算),左右分别为 true 和 false 共四种情况(左T右F,右T左F,左T右T,左F右F)
四种组合以不同的逻辑运算组合出不同的结果,根据想获得的结果进行不同的逻辑运算以及两边取不同的值(比如结果想获得true,则取 T&T,T|F,F|T ,T^F,F^T )
根据不同的逻辑运算符可能获得期望结果的左右布尔值,以此进行递归。
递归:(会超时)
import java.util.Scanner;
public class Main {
public static long MOD_NUM=1000000007;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String str=sc.nextLine();
boolean desired=sc.nextBoolean();
System.out.println(dfs(str, desired, 0, str.length() - 1));
}
public static long dfs(String str,boolean desired,int L,int R){
if(L==R){
if(str.charAt(L)=='1'){
return desired ? 1 : 0;
}else {
return desired ? 0 : 1;
}
}
long res=0;
if(desired){
for(int i=L+1;i<R;i=i+2){
switch (str.charAt(i)){
case '&':
res+=dfs(str,true,L,i-1)*dfs(str,true,i+1,R);
break;
case '|':
res+=dfs(str,true,L,i-1)*dfs(str,true,i+1,R);
res+=dfs(str,false,L,i-1)*dfs(str,true,i+1,R);
res+=dfs(str,true,L,i-1)*dfs(str,false,i+1,R);
break;
case '^':
res+=dfs(str,false,L,i-1)*dfs(str,true,i+1,R);
res+=dfs(str,true,L,i-1)*dfs(str,false,i+1,R);
break;
}
}
}else {
for (int i=L+1;i<R;i=i+2){
switch (str.charAt(i)){
case '&':
res+=dfs(str,false,L,i-1)*dfs(str,true,i+1,R);
res+=dfs(str,true,L,i-1)*dfs(str,false,i+1,R);
res+=dfs(str,false,L,i-1)*dfs(str,false,i+1,R);
break;
case '|':
res+=dfs(str,false,L,i-1)*dfs(str,false,i+1,R);
break;
case '^':
res+=dfs(str,false,L,i-1)*dfs(str,false,i+1,R);
res+=dfs(str,true,L,i-1)*dfs(str,true,i+1,R);
break;
}
}
}
return res%MOD_NUM;
}
}
动态规划:
以空间换时间,将 true 和 false 分别存储至 length*lenth的二位数组表(i,j)位置表示,从字符串的 i 位置运算至 j 位置的为真或假的组合数(真填入T,假填入F),且 i 位置一定在 j 位置之前,当 i=j 时 此时str[i] = '0' ,则为 false 表(i,j)位置的一种情况,str[i]='1',则为 true 表(i,j)位置的一种情况,所以对于二维数组,可以先填入对角线的情况,由左至右,由下至上,得出二维数组左上角的值(0,length-1),此时二位数组true的值代表的含义即为从0遍历到length-1(字符串全部长度)结果为true的组合数,二位数组false的值代表的含义即为从0遍历到length-1(字符串全部长度)结果为false的组合数。
import java.util.Scanner;
public class Main {
public static long MOD_NUM=1000000007;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String str=sc.nextLine();
boolean desired=sc.nextBoolean();
if (Judge(str)){
System.out.println(Combination(str,desired));
}else {
System.out.println(0);
}
}
public static boolean Judge(String str){
if((str.length()&1)==0){
return false;
}
for (int i = 0; i < str.length(); i=i+2) {
if(str.charAt(i)!='0'&&str.charAt(i)!='1'){
return false;
}
}
for(int i=1;i<str.length();i=i+2){
if(str.charAt(i)!='&'&&str.charAt(i)!='^'&&str.charAt(i)!='|'){
return false;
}
}
return true;
}
public static long Combination(String str,boolean desired){
long[][] ArrT=new long[str.length()][str.length()];
long[][] ArrF=new long[str.length()][str.length()];
for (int i = 0; i < str.length(); i=i+2) {
if(str.charAt(i)=='1'){
ArrF[i][i]=0;
ArrT[i][i]=1;
}else {
ArrF[i][i]=1;
ArrT[i][i]=0;
}
}
long CombineT,CombineF;
for(int len=2;len<str.length();len+=2)
{
for(int i=0;i+len<str.length();i+=2)
{
CombineT=0;
CombineF=0;
for(int j=i+1;j<i+len;j+=2)
{
switch (str.charAt(j)){
case '&':
//T & T = T
CombineT+=ArrT[i][j-1]*ArrT[j+1][i+len];
//T & F = F
CombineF+=ArrT[i][j-1]*ArrF[j+1][i+len];
//F & T = F
CombineF+=ArrF[i][j-1]*ArrT[j+1][i+len];
//F & F = F
CombineF+=ArrF[i][j-1]*ArrF[j+1][i+len];
CombineT=CombineT%MOD_NUM;
CombineF=CombineF%MOD_NUM;
break;
case '|':
// T | T = T
CombineT+=ArrT[i][j-1]*ArrT[j+1][i+len]%MOD_NUM;
// T | F = T
CombineT+=ArrT[i][j-1]*ArrF[j+1][i+len]%MOD_NUM;
// F | T = T
CombineT+=ArrF[i][j-1]*ArrT[j+1][i+len]%MOD_NUM;
// F | F = F
CombineF+=ArrF[i][j-1]*ArrF[j+1][i+len]%MOD_NUM;
CombineT=CombineT%MOD_NUM;
CombineF=CombineF%MOD_NUM;
break;
case '^':
// T ^ F = T
CombineT+=ArrT[i][j-1]*ArrF[j+1][i+len];
// F ^ T = T
CombineT+=ArrF[i][j-1]*ArrT[j+1][i+len];
// T ^ T = F
CombineF+=ArrT[i][j-1]*ArrT[j+1][i+len];
// F ^ F = F
CombineF+=ArrF[i][j-1]*ArrF[j+1][i+len];
CombineT=CombineT%MOD_NUM;
CombineF=CombineF%MOD_NUM;
break;
}
}
ArrT[i][i+len]=CombineT%MOD_NUM;
ArrF[i][i+len]=CombineF%MOD_NUM;
}
}
if(desired)
return ArrT[0][str.length() - 1];
else
return ArrF[0][str.length() - 1];
}
}