码迷,mamicode.com
首页 > 其他好文 > 详细

[loj3463]表达式求值

时间:2021-02-08 11:56:15      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:merge   int   code   树形dp   blog   i++   接下来   spl   char   

类似cf582E,先建出表达式树,然后树形dp+离散+min和max卷积的优化,复杂度为$o(nm|E|)$,无法通过

考虑我们仅关心于这$n$个数的大小关系,具体来说,假设给出的数组是$a_{i,j}$(其中$0\le i<m,1\le j\le n$),对于某一个$j$,将$a_{i,j}$从小到大排序后,依次是$a_{p_{i},j}$($0\le i<m$,$p_{i}$为$[0,m)$的一个排列)

暴力枚举$j$和$p_{i}$,接下来去统计答案不小于$a_{p_{i},j}$的方案数:

对于树形dp的状态上,我们仅需要记录小于$a_{p_{i},j}$和不小于$a_{p_{i},j}$的方案数,换言之是$o(1)$转移,但dp次数为$o(nm)$,因此总复杂度仍然是$o(nm|E|)$

但注意到,影响dp过程的只有对于每一个$i$,$[a_{i,j}\ge a_{p_{i},j}]$的值,不难发现至多$2^{m}$种,预处理出每一种值的结果,再枚举$j$和$p_{i}$求出是哪一种值即可

时间复杂度为$o(2^{m}|E|+nm)$,可以通过

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 50005
 4 #define mod 1000000007
 5 stack<int>st_op,st_num;
 6 int V,n,m,p,ans,b[11][N],a[N],ls[N],rs[N],id[11],f[1<<10][N][2];
 7 char s[N];
 8 bool cmp(int x,int y){
 9     return b[x][p]>b[y][p];
10 }
11 void merge(){
12     a[++V]=st_op.top();
13     st_op.pop();
14     rs[V]=st_num.top();
15     st_num.pop();
16     ls[V]=st_num.top();
17     st_num.pop();
18     st_num.push(V);
19 }
20 void dfs(int k,int p){
21     if ((!ls[k])&&(!rs[k])){
22         f[p][k][((p&(1<<a[k]))>0)]=1;
23         return;
24     }
25     dfs(ls[k],p);
26     dfs(rs[k],p);
27     int s=(1LL*f[p][ls[k]][0]*f[p][rs[k]][1]+1LL*f[p][ls[k]][1]*f[p][rs[k]][0])%mod;
28     if (a[k]==0){
29         f[p][k][0]=(1LL*f[p][ls[k]][0]*f[p][rs[k]][0]+s)%mod;
30         f[p][k][1]=1LL*f[p][ls[k]][1]*f[p][rs[k]][1]%mod;
31     }
32     if (a[k]==1){
33         f[p][k][0]=1LL*f[p][ls[k]][0]*f[p][rs[k]][0]%mod;
34         f[p][k][1]=(1LL*f[p][ls[k]][1]*f[p][rs[k]][1]+s)%mod;
35     }
36     if (a[k]==2){
37         f[p][k][0]=(2LL*f[p][ls[k]][0]*f[p][rs[k]][0]+s)%mod;
38         f[p][k][1]=(2LL*f[p][ls[k]][1]*f[p][rs[k]][1]+s)%mod;
39     }
40 }
41 int main(){
42     scanf("%d%d",&n,&m);
43     for(int i=0;i<m;i++)
44         for(int j=1;j<=n;j++)scanf("%d",&b[i][j]);
45     scanf("%s",s);
46     int l=strlen(s),flag=0;
47     for(int i=0;i<l;i++)
48         if ((0<=s[i])&&(s[i]<=9)){
49             a[++V]=s[i]-0;
50             st_num.push(V);
51             if ((!st_op.empty())&&(st_op.top()!=-1))merge();
52         }
53         else{
54             if (s[i]==()st_op.push(-1);
55             if (s[i]==<)st_op.push(0);
56             if (s[i]==>)st_op.push(1);
57             if (s[i]==?){
58                 st_op.push(2);
59                 flag=1;
60             }
61             if (s[i]==)){
62                 st_op.pop();
63                 if ((!st_op.empty())&&(st_op.top()!=-1))merge();
64             }
65         }
66     while (!st_op.empty())merge();
67     for(int i=0;i<(1<<m);i++)dfs(V,i);
68     for(int i=1;i<=n;i++){
69         for(int j=0;j<m;j++)id[j]=j;
70         p=i;
71         sort(id,id+m,cmp);
72         id[m]=m;
73         int s=0;
74         for(int j=0;j<m;j++){
75             s|=(1<<id[j]);
76             ans=(ans+1LL*f[s][V][1]*(b[id[j]][i]-b[id[j+1]][i]))%mod;
77         }
78     }
79     printf("%d",ans);
80     return 0;
81 }
View Code

 

[loj3463]表达式求值

标签:merge   int   code   树形dp   blog   i++   接下来   spl   char   

原文地址:https://www.cnblogs.com/PYWBKTDA/p/14382818.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!