ICPC World Finals 2019 D

转化之后的题意:

给出一个环,每个位置都是一种颜色的左括号或右括号

寻找一个环的切割位置,满足从这个位置切割之后得到的链中,单独看每一种颜色的括号能够匹配的颜色种类数最大

输出最小的切割位置和最大匹配的种类数

单独看一种颜色的括号

左括号+1,右括号-1

如果一个位置切割之后满足条件,那么

要求这种颜色所有的加1减1之和为0

而且是是前缀和最小的位置

这个位置直到下一个同颜色的位置之间都可以作为切割点

把所颜色的这些区间找出来即可

复杂度分析

最多一个左括号产生一个区间

所以有O(n)个区间

#include<cstdio>
#include<vector>
#include<algorithm> 

using namespace std;

#define N 1000005

#define lowbit(x) x&-x

struct node
{
    int val,pos;
}tmp;
vector<node>v[N];

int n,c[N];
int tot[N];

int main()
{
    int x;
    char cc;
    scanf("%d",&n);
    int m=0;    
    for(int i=1;i<=n;++i)
    {
        cc=getchar();
        cc=getchar();
        scanf("%d",&x);
        m=max(m,x); 
        tmp.pos=i;
        if(cc=='s')
        {
            tmp.val=1;
            tot[x]++;
        }
        else
        {
            tmp.val=-1;
            tot[x]--;
        }
        v[x].push_back(tmp);
    }
    int len;
    int mi,l,r,now;
    for(int i=1;i<=m;++i)
    {
        len=v[i].size();
        if(!len || tot[i]) continue;
        now=0;
        mi=0;
        for(int j=0;j<len;++j)
        {
            now+=v[i][j].val;
            if(now<mi) mi=now;
        }
        now=0;
        if(now==mi)
        {
            c[1]++;
            c[v[i][0].pos+1]--; 
        }
        for(int j=0;j<len;++j)
        {
            now+=v[i][j].val;
            if(now==mi)
            {
                c[v[i][j].pos+1]++;
                if(j!=len-1) c[v[i][j+1].pos+1]--;
            }
        }
    }
    int mx=-1,ans=0;
    for(int i=1;i<=n;++i)
    {
        now+=c[i];
        if(now>mx)
        {
            mx=now;
            ans=i;
        }
    } 
    printf("%d %d",ans,mx);
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/14090394.html