题目链接
题目解法
不错的题
首先建出表达式树
说实话我一开始不知道怎么建,但看了代码之后就懂了
这里简单说一下:假如要对区间 \([l,r]\) 建树,分 \(E_r=)\) 和 \(E_r\neq )\) 的情况
- \(E_r=)\),找到匹配的左括号,递归下去建树
- \(E_r\neq )\),\(r\) 可以作为单独的一个叶子,于是递归到 \([l,r-2]\) 和 \([r,r]\) 建树
\(O(n|E|m)\) 是显然的
首先肯定是拆成数组的每一位做
里面做一遍树形 \(dp\) 即可,即 \(f_{i,j}\) 表示在结点 \(i\) 的结果为第 \(j\) 个数组的值,不难转移
考虑如何优化
这一步优化很巧妙,枚举最后的结果为第 \(x\) 个数组,记第 \(x\) 个数组当前位的值为 \(v\)(如果数值相同可以按照字典序排),那么最后的方案数只与比 \(v\) 大的集合有关,不妨枚举这个集合为 \(S\)
不难得到树形 \(dp\) 为 \(f_{i,0/1/2}\) 表示在结点 \(i\) 的结果为 \(<v/=v/>v\) 的方案数,转移显然
最后值为 \(v\) 的方案数即为 \(f_{rt,1}\)
但这样的复杂度仍是 \(O(m2^m|E|)\),不能通过
考虑进一步优化,即如何不枚举 \(x\)
这里我们把最后的值类似地转成差分的形式,即我们改变最后需要求得的答案:最终结果 $\ge $ 在集合 \(S\) 中的方案数
这样只要令 \(f_{i,0/1}\) 表示结点 \(i\) 的结果为 \(<v/\ge v\) 的方案数
复杂度就降为了 \(O(2^m|E|)\)
最后统计答案显然
时间复杂度为 \(O(2^m|E|+nm\log m)\)
#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
const int N=50010,M=10,P=1e9+7;
int n,m,a[M][N],id[M],g[1<<M];
char str[N];
int stk[N],top,brc[N];
int op[N],ind[N],lc[N],rc[N],idx;
int Get(int p){ if(str[p]=='>') return 1;if(str[p]=='<') return 0;return 2;}
int build(int l,int r){
if(brc[r]){
if(brc[r]==l) return build(l+1,r-1);
int p=++idx;op[p]=Get(brc[r]-1);
rc[p]=build(brc[r]+1,r-1),lc[p]=build(l,brc[r]-2);
return p;
}
int p=++idx;
if(l==r){ ind[p]=str[l]-48;return p;}
op[p]=Get(r-1),rc[p]=build(r,r),lc[p]=build(l,r-2);
return p;
}
int State,f[N][2];
inline void inc(int &x,int y){ x+=y;if(x>=P) x-=P;}
void dfs(int u){
if(!lc[u]){ f[u][State>>ind[u]&1]=1;return;}
dfs(lc[u]),dfs(rc[u]);
if(op[u]==1||op[u]==2) F(i,0,1) F(j,0,1) inc(f[u][max(i,j)],1ll*f[lc[u]][i]*f[rc[u]][j]%P);
if(!op[u]||op[u]==2) F(i,0,1) F(j,0,1) inc(f[u][min(i,j)],1ll*f[lc[u]][i]*f[rc[u]][j]%P);
}
int main(){
n=read(),m=read();
F(i,0,m-1) F(j,1,n) a[i][j]=read();
scanf("%s",str+1);
int len=strlen(str+1);
F(i,1,len){
if(str[i]=='(') stk[++top]=i;
if(str[i]==')') brc[i]=stk[top],brc[stk[top]]=i,top--;
}
ms(ind,-1);
int rt=build(1,len);
F(S,0,(1<<m)-1){
ms(f,0);State=S,dfs(rt);
g[S]=f[rt][1];
}
int ans=0;
F(i,1,n){
F(j,0,m-1) id[j]=j;
sort(id,id+m,[&](int x,int y){ return a[x][i]>a[y][i];});
int St=0;inc(ans,1ll*g[(1<<m)-1]*a[id[m-1]][i]%P);
F(j,0,m-2) St|=1<<id[j],inc(ans,1ll*g[St]*(a[id[j]][i]-a[id[j+1]][i])%P);
}
printf("%d\n",ans);
return 0;
}
标签:ch,lc,int,题解,P7324,read,str,求值,define
From: https://www.cnblogs.com/Farmer-djx/p/17993588