2018杭电多校第一场(hdu 6299,hdu 6301)

hdu6299  Balanced Sequence

题解:因为是从子序列里面选择括号,所以只要前面有一个左括号‘( ’后面有一个右括号,那就能组成一个合法的括号组合,所以对字符串进行重新排序的时候,要满足让左括号尽量在前面,右括号尽量在后面,而一个字符串自己原串中能组成合法的括号就不用再次判断了。所以我们对每个字符串需要统计的有三个东西,它里面能配成对的对数,落单的左括号数,落单的右括号数。然后对这些字符串进行排序,排序的规则是:题意:给n个字符串,每个字符串是长度不超过1e5的只由' ( '和' ) '组成的串,可以调整不同的串的顺序,但是不能改变一个串自己内部括号的顺序,问最多能组成的合法括号组合的长度。

①. 当左括号多右括号少的字符串c1遇上左括号少的右括号多的字符串c2,c1排在c2前面。(满足左括号尽量在前面,右括号尽量在后面)

②. 当两个字符串都是左括号少右括号多的字符串,按照它们左括号的数量排序。

③其他情况都按照右括号的数量排序。

附上代码:

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int l,r,nu;//l左括号,r右括号
     bool operator < (const node& aa)const
    {
        if(l<=r&&aa.l>aa.r)//左少右多 & 左多右少
        {
            return false;
        }
        if(l>r&&aa.l<=aa.r)//左多右少 & 左少右多
        {
            return true;
        }
        if(r>=l&&aa.r>=aa.l)//左少右多 &7左少右多
        {
            return l>aa.l;
        }
        return r<aa.r;//其他情况按右括号的顺序排序
    }
}a[100010];
char ss[100010];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
           {
               scanf("%s",ss);
               int len=strlen(ss);
               int num1=0,num2=0,num=0;
               for(int j=0;j<len;j++)
               {
                   if(ss[j]=='(')
                        num1++;
                   else {
                        if(num1)
                        num++,num1--;
                   else
                        num2++;
                   }
               }
               a[i].l=num1;
               a[i].r=num2;
               a[i].nu=num;
           }
           sort(a,a+n);
           //for(int i=0;i<n;i++)
            //printf("%d  %d  %d\n",a[i].l,a[i].r,a[i].nu);
           long long ans=0;
           long long pre=0;
           for(int i=0;i<n;i++)
           {
               ans+=a[i].nu;
               if(pre&&a[i].r)
               {
                   if(pre>a[i].r)
                   {
                       ans+=a[i].r;
                       pre-=a[i].r;
                   }
                   else ans+=pre,pre=0;
               }
               pre+=a[i].l;
           }
           printf("%lld\n",ans*2);
    }
    return 0;
}

hdu 6301 Distinct Values

题意:有一个长度为n的数字序列,给m个要求,每次要求包括一个区间左右端点,要求在给出的这个区间中的数字没有重复的,同时要求数字序列字典序最小,输出这个数字序列。

题解:贪心,对于任何一个位置能填最小的就填最小的,所以对于要求的区间我们按左端点排序,然后从左往右扫过去,对于一个区间没有与其他区间有重合部分的话,就从1开始递增填数,否则,我们用一个优先队列,将有重合区间的非重合部分里填的数放入队列,这部分数就是当前区间没填数的部分可以填的,当队列里的数全部被用完了区间还没完,我们就从上一个区间的最大的数的下一个数开始填,所以需要记录在每个区间里面出现的最大的数,至于判断两区间是否重合可以用一个变量存每个区间的端点就行了。

附上代码:

#include<bits/stdc++.h>
using namespace std;
int ans[100005];
struct node {
    int l,r;
    bool operator<(const node&aa)const
    {
        return aa.l>l;
    }
}a[100005];
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0; i<m; i++)
            scanf("%d%d",&a[i].l,&a[i].r);
        sort(a,a+m);
        for(int i=1; i<=n; i++)
            ans[i] = 1;
        int l = 0,r = 0;
        int maxx = 0;
        priority_queue<int,vector<int>,greater<int> >q;
        for(int i=0; i<m; i++) {
            if(a[i].r<=r)
                continue;
            if(a[i].l>r)
            {
                for(int j=a[i].l,k=1; j<=a[i].r; j++,k++)
            {
                    ans[j] = k;
                    maxx = k;
                }
                l = a[i].l,r = a[i].r;
                while(!q.empty())
                  q.pop();
            }
             else {
                for(int j=l; j<a[i].l; j++)
                    q.push(ans[j]);
                for(int j=r+1; j<=a[i].r; j++) {
                    if(!q.empty()) {
                        ans[j]= q.top();
                        q.pop();
                    }
                    else
                    {
                        ans[j] = ++maxx;
                    }
                }
                l = a[i].l;
                r = a[i].r;
            }
        }
        for(int i=1; i<n; i++) {
            printf("%d ",ans[i]);
        }
        printf("%d\n",ans[n]);
    }
    return 0;

}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值