「HNSDFZ暑期集训 测试1」「LuoguT36485」 括号(贪心

Description


给定一个由左括号'('和右括号')'组成的字符串s,其中第i个括号的权值为ai。

我们定义一个括号序列t为合法括号序列,当且仅当满足下列条件之一:

1.t为空串

2.t=(A),其中A为一个合法括号序列

3.t=AB,其中A,B均为合法括号序列

比如(()()),()(())均为合法括号序列,但((), ())(不是合法括号序列。

Input


输入第一行一个整数n,表示s的长度。

第二行一个长度为n,且由括号组成的字符串s。

第三行n个整数,第i个整数ai表示第i个括号的值。

Output


输出仅一行一个整数,表示答案。

Sample Input1


6
())(()
1 2 1 2 1 2

Sample Output1


7

Sample Input2


6
((()))
2 1 -2 1 2 3

Sample Output2


8

Hint


40%的数据n<=20,0<=ai<=100

接下来30%的数据 n<=2000,|ai|<=1e5

接下来30%的数据 n<=2e5,|ai|<=1e3,左括号全都在右括号的左边

题解


官方题解:

分情况讨论 
n<=2000时 用dp,F [ i ] [ j ]表示前i个中有j个左括号时的最大值
n >2000时,分别对左括号的值和右括号的值排序(cmp从大到小),用for循环从1走一遍,若a[i]+b[i]>0 ans+=a[i]+b[i],否则return.

但是我的思路可以把n取到1e6并且不需要特殊性质啊!QAQ

我们先假设现在已经从头开始扫了一段括号序列,并且前一段已经标记了最优的序列有哪些括号。对于现在新加进来的括号,我们仍然要试图维持当前选择最优。

如果是左括号,我们不做任何处理(也做不了什么);

如果是右括号,那么不外乎三种情况:

1.不做任何处理;

2.在这个右括号之前找一个未被选的左括号,与其配对(标记此左括号和右括号);

3.在这个右括号之前找一个被选了的右括号,将其替代(清除前面的右括号的标记,并且标记新的右括号)

只要在这三种操作中取一个最优操作,就仍然可以保持当前最优。

那么,用一个for从头至尾循环,复杂度O(n),

对每个当前括号,做以上判断,

其中的往前找要求的括号的操作(2)和操作(3)可以用堆实现,复杂度O(logn)

一共O(nlogn)

代码://考场代码 因为可以水到分所以懒得写堆了(其实可以直接调用priority_queue 也很方便)

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cmath>
  5 using namespace std;
  6 int s[200007];
  7 int q[200007];
  8 bool sf[200007];
  9 int a[200007];
 10 int b[200007];
 11 bool cmp(int qaq,int qwq)
 12 {
 13     return qaq>qwq;
 14 }
 15 int main()
 16 {
 17     int n;
 18     cin>>n;
 19     if(n<2001)
 20     {
 21     for(int i=1;i<=n;++i)
 22     {
 23         char x;
 24         cin>>x;
 25         if(x=='(')s[i]=1;
 26         else s[i]=2;
 27     }
 28     for(int i=1;i<=n;++i)
 29     {
 30         cin>>q[i];
 31         //cout<<i<<" "<<s[i]<<" "<<a[i]<<endl;
 32         if(s[i]==2)
 33         {
 34             int u=-99999999,pu=0;
 35             for(int j=i-1;j;--j)
 36             if(s[j]==1&&!sf[j])
 37             {
 38                 if(q[j]>u){u=q[j];pu=j;}
 39             }
 40             int v=99999999,pv=0;
 41             for(int j=i-1;j;--j)
 42             if(s[j]==2&&sf[j])
 43             {
 44                 if(q[j]<v){v=q[j];pv=j;}
 45             }
 46             //cout<<u<<" "<<pu<<" "<<v<<" "<<pv;
 47             if(pu&&pv)
 48             {
 49             if(u+q[i]>=q[i]-v&&u+q[i]>0)
 50             {
 51                 sf[pu]=1;sf[i]=1;
 52             }
 53             else if(q[i]-v>u+q[i]&&q[i]-v>0)
 54             {
 55                 sf[pv]=0;sf[i]=1;
 56             }
 57             }
 58             else
 59             {
 60                 if(pu&&u+q[i]>0)
 61                 {
 62                     sf[pu]=1;sf[i]=1;
 63                 }
 64                 else if(pv&&q[i]-v>0)
 65                 {
 66                     sf[pv]=0;sf[i]=1;
 67                 }
 68             }
 69             //cout<<endl;
 70         }
 71     }
 72     int ans=0;
 73     for(int i=1;i<=n;++i)
 74     if(sf[i]){ans+=q[i];}
 75     cout<<ans;//强大怪!!! 
 76     return 0;
 77     }
 78     else
 79     {
 80     for(int i=1;i<=n;++i)
 81     {
 82         char x;
 83         cin>>x;
 84         if(x=='(')s[i]=1;
 85         else s[i]=2;
 86     }
 87     int toa=0,tob=0;
 88     for(int i=1;i<=n;++i)
 89     {
 90         int x;
 91         scanf("%d",&x);
 92         if(s[i]==1)a[++toa]=x;
 93         else b[++tob]=x;
 94     }
 95     sort(a+1,a+toa+1,cmp);
 96     sort(b+1,b+tob+1,cmp);
 97     int ans=0;
 98     for(int i=1;i<=min(toa,tob);++i)
 99     {
100         if(a[i]+b[i]>0)ans+=(a[i]+b[i]);
101         else {cout<<ans;return 0;}
102     }
103     cout<<ans;//强大怪!!! 
104     return 0;
105     }
106 }
107 //注释强大怪 你会rp++

UPD

$O(nlogn)$的堆写法↓

 1 /*
 2 qwerta 
 3 T36485 括号 Accepted 
 4 100
 5 代码 C++,0.7KB
 6 提交时间 2018-11-05 20:42:18
 7 耗时/内存 442ms, 2124KB
 8 */
 9 #include<iostream>
10 #include<cstdio>
11 #include<queue>
12 using namespace std;
13 char ch[200003];
14 int v[200003];
15 priority_queue<int,vector<int>,greater<int> >r;//r放右括号
16 priority_queue<int>l;//l放左括号
17 int main()
18 {
19     //freopen("a.in","r",stdin);
20     ios::sync_with_stdio(false);
21     int n;
22     cin>>n;
23     for(int i=1;i<=n;++i)
24     cin>>ch[i];
25     for(int i=1;i<=n;++i)
26     cin>>v[i];
27     //
28     int ans=0;
29     for(int i=1;i<=n;++i)
30     {
31         if(ch[i]=='(')
32         {
33             l.push(v[i]);
34         }
35         else
36         {
37             int x,y;
38             if(l.empty())x=-1;//赋成-1不碍事儿
39             else x=v[i]+l.top();
40             if(r.empty())y=-1;
41             else y=v[i]-r.top();
42             if(x>=y&&x>=0)//找个没用过的左括号
43             {
44                 ans+=x;
45                 l.pop();
46                 r.push(v[i]);
47             }
48             else if(y>=x&&y>=0)//替代一个用过的右括号
49             {
50                 ans+=y;
51                 r.pop();
52                 r.push(v[i]);
53             }
54         }
55     }
56     cout<<ans;
57     return 0;
58 }
原文地址:https://www.cnblogs.com/qwerta/p/9379746.html