[codechef] REBIT:準備好每一位(表示式/DP)
阿新 • • 發佈:2020-11-17
Problem
Solution
前置知識
中綴表示式序列可以轉化成一棵二叉樹。發現計算概率可以轉化成計數,在二叉樹上做一個樹形DP就好了。
Code
Talk is cheap.Show me the code.
#include<bits/stdc++.h> using namespace std; typedef int LL; #define int long long inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } return x * f; } const int N = 1e6+7, mod = 998244353; int len,tot; int ls[N],rs[N]; int f[N][4]; char str[N],c[N]; struct Node { int x,y; Node operator & (const Node &el) const { return (Node)<%x&el.x, y&el.y%>; } Node operator | (const Node &el) const { return (Node)<%x|el.x, y|el.y%>; } Node operator ^ (const Node &el) const { return (Node)<%x^el.x, y^el.y%>; } bool operator < (const Node &el) const { return (x==el.x ? y<el.y : x<el.x); } }; map<int,Node> inode; map<Node,int> acinode; void Init() { inode[0] = (Node)<%0,0%>, inode[1] = (Node)<%1,1%>, inode[2] = (Node)<%0,1%>, inode[3] = (Node)<%1,0%>; acinode[(Node)<%0,0%>] = 0, acinode[(Node)<%1,1%>] = 1, acinode[(Node)<%0,1%>] = 2, acinode[(Node)<%1,0%>] = 3; } inline void Add(int &x,int y) { x = (x+y>mod ? x+y-mod : x+y); } void Dfs(int u) { int x = ls[u], y = rs[u]; if(x) { Dfs(x); Dfs(y); } else return ; for(int i=0;i<4;++i) { Node ii = inode[i]; for(int j=0;j<4;++j) { Node jj = inode[j]; if(c[u] == '&') { Add(f[u][acinode[ii & jj]], f[x][i]*f[y][j]%mod); } else if(c[u] == '|') { Add(f[u][acinode[ii | jj]], f[x][i]*f[y][j]%mod); } else if(c[u] == '^') { Add(f[u][acinode[ii ^ jj]], f[x][i]*f[y][j]%mod); } } } } int Pow(int x,int y) { int res = 1, base = x; while(y) { if(y&1) res = res*base%mod; base = base*base%mod; y >>= 1; } return res; } void work() { for(int i=1;i<=tot;++i) { c[i] = ls[i] = rs[i] = 0; for(int j=0;j<4;++j) f[i][j] = 0; } tot = 0; scanf("%s",str+1); len = strlen(str+1) stack<char> sta; stack<int> num; for(int i=0;i<=len+1;++i) { if(str[i] == '(') { sta.push(str[i]); } else if(str[i] == ')') { while(sta.top() != '(') { char opt = sta.top(); sta.pop(); int x = num.top(); num.pop(); int y = num.top(); num.pop(); c[++tot] = opt; ls[tot] = y, rs[tot] = x; num.push(tot); } sta.pop(); } else if(str[i] == '#') { c[++tot] = str[i]; num.push(tot); } else { sta.push(str[i]); } } for(int i=1;i<=tot;++i) { if(!ls[i]) { for(int j=0;j<4;++j) f[i][j] = 1; } } Dfs(tot); int sum = 0; for(int i=0;i<4;++i) Add(sum, f[tot][i]); int inv = Pow(sum,mod-2); for(int i=0;i<4;++i) printf("%lld ",f[tot][i]*inv%mod); puts(""); } signed main() { Init(); int T = read(); while(T--) work(); return 0; } /* 2 # (#&#) () 748683265 748683265 748683265 748683265 436731905 935854081 811073537 811073537 */
Summary
- 中綴表示式序列可以轉化成一棵二叉樹。從而將此類問題轉化為樹上問題。