这道题的trick我见过好几次了。
但是在考场上一点印象也没有。
还好在学普及组时学了表达式树,成功获得70分。
先建立原串的表达式树。
容易发现数组的每个元素是独立的。
于是问题转化为:(O(n))次给定一个数组(ar),给定一个固定的树,每个叶子节点上有固定的权值(b)。
询问时把叶子节点(i)权值改为(ar_{b_i})
树上每个非叶子节点是(min)或者(max)节点,表示这个节点的值是儿子节点的(min)或者(max)。询问根节点的值。
根节点的值只有(O(m))种,考虑每个值对答案的贡献,设值(v)出现了(y_v)次,就是(sum_i y_v*v)。
使用等于转大于转化,就是要求(sum_i [igeq a_i]),其中(a)是值的数组。
把(a)从小到大排序。显然(a_{i-1}+1 o a_i)的([igeq a_i])是相同的,可以把([igeq a_i])算出后累加(a_i-a_{i-1})次。
接下来就只用关心每个值和(i)的大小关系。
根据heoi某题,把(geq i)的赋值成(1),把(<i)的赋值为0。求出根节点为(0/1)的方案数,可以用dp。
设(f_{i,0/1})表示以(i)为根的子树的值为(0/1)的方案数,转移显然。
但是这样子对时间复杂度没有改进。
由于(m)非常小,所以可以预处理出(2^m)种叶子结点取值为(0/1)的情况,然后可以(O(1))查询。
最终时间复杂度(O(nmlog_2m+|E|2^m))
#include<bits/stdc++.h>
using namespace std;
#define mo 1000000007
#define N 200010
#define int long long
struct no{
int x,y;
}s2[N],b[N];
int operator <(no x,no y){
return x.x<y.x;
}
int operator ==(no x,no y){
return x.x==y.x;
}
int n,m,a[N][12],ct,s1[N],t1,t2,op[N],lc[N],rc[N],s3[N],s4[N],ans[N][2],f[N][2],rt,va[N];
char s[N];
void dfs(int x){
int l=lc[x],r=rc[x];
if(l)
dfs(l);
if(r)
dfs(r);
if(!l&&!r)
f[x][va[x]]=1;
else{
if(op[x]!=-1){
f[x][1]=(f[l][1]*f[r][1]%mo+f[l][0]*f[r][1]%mo+f[l][1]*f[r][0]%mo)%mo;
f[x][0]=f[l][0]*f[r][0]%mo;
}
if(op[x]!=-2){
f[x][1]=(f[x][1]+f[l][1]*f[r][1])%mo;
f[x][0]=(f[x][0]+f[l][0]*f[r][0]%mo+f[l][1]*f[r][0]%mo+f[l][0]*f[r][1]%mo)%mo;
}
}
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=0;i<m;i++)
for(int j=1;j<=n;j++)
scanf("%lld",&a[j][i]);
scanf("%s",s+1);
int l=strlen(s+1);
s[0]='(';
s[l+1]=')';
for(int i=0;i<=l+1;i++){
if(isdigit(s[i])){
s1[++t1]=++ct;
op[ct]=s[i]-'0';
}
else if(s[i]=='>'||s[i]=='<'||s[i]=='?'){
s2[++t2]=(no){++ct,1};
if(s[i]=='<')
op[ct]=-1;
else if(s[i]=='>')
op[ct]=-2;
else
op[ct]=-3;
}
else if(s[i]=='(')
s2[++t2]=(no){0,0};
else{
int t3=0,t4=0,cc=0;
while(s2[t2].y){
s3[++t3]=s2[t2].x;
t2--;
cc++;
}
t2--;
for(int j=1;j<=cc+1;j++){
s4[++t4]=s1[t1];
t1--;
}
reverse(s4+1,s4+t4+1);
reverse(s3+1,s3+t3+1);
int la=s4[1],ll;
for(int i=1;i<=t3;i++){
lc[s3[i]]=la;
rc[s3[i]]=s4[i+1];
la=s3[i];
rt=s3[i];
}
s1[++t1]=la;
}
}
for(int i=0;i<(1<<m);i++){
for(int j=1;j<=ct;j++)
va[j]=f[j][0]=f[j][1]=0;
for(int j=1;j<=ct;j++)
if(op[j]>=0){
if(i&(1<<op[j]))
va[j]=1;
else
va[j]=0;
}
dfs(rt);
ans[i][0]=f[rt][0];
ans[i][1]=f[rt][1];
}
int vv=0;
for(int i=1;i<=n;i++){
for(int j=0;j<m;j++)
b[j]=(no){a[i][j],j};
sort(b,b+m);
reverse(b,b+m);
int va=0;
for(int j=1;j<=m;j++){
for(int k=0;k<m;k++)
if((!(va&(1<<b[k].y)))&&b[j-1].x==b[k].x)
va+=(1<<b[k].y);
vv=(ans[va][1]*(b[j-1].x-b[j].x)%mo+vv)%mo;
}
}
printf("%lld",vv);
}