zoukankan      html  css  js  c++  java
  • [loj3463]表达式求值

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

    考虑我们仅关心于这$n$个数的大小关系,具体来说,假设给出的数组是$a_{i,j}$(其中$0le i<m,1le jle n$),对于某一个$j$,将$a_{i,j}$从小到大排序后,依次是$a_{p_{i},j}$($0le 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
  • 相关阅读:
    using 关键字有两个主要用途:
    Pl/SQL 从零开始
    SQL从零开始
    wcf 从零开始
    设置主键
    dbf导入sqlserver
    SHBrowseForFolder
    oracle 导入导出数据库
    sql改列名
    Delphi 为Edit或是Memo添加一个气球提示
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14382818.html
Copyright © 2011-2022 走看看