codeforces educational round 105 题解

codeforces educational round 105 题解

A

一串只带有A,B,C的字符串,用“(”或“)”替换其中的字母,问能否构成正则表达式

验证正则表达式的思路很常规,见左括号加1,右括号减1,中间不能出现负号,且最后的结果为0。枚举A,B,C分别为“(”或“)”的情况,共8种。

#include<bits/stdc++.h>
#define MAXN 200000
using namespace std;
int T,val[5][10];
string s;
int main()
{
    cin >> T;

    int tot = -1;
    for (int i = -1; i <= 1;i+=2)
        for (int j = -1; j <= 1;j+=2)
            for (int k = -1; k <= 1;k+=2)
            {
                tot++;
                val[0][tot] = i;
                val[1][tot] = j;
                val[2][tot] = k;
            }


    while(T--)
    {
        cin >> s;
        bool jud = 0;
        for (int i = 0; i < 8;i++)
        {
            int ans = 0;
            for (int j = 0; j < s.length();j++)
            {
                if(ans<0)
                    break;
                ans += val[s[j] - 'A'][i];
            }
            if(ans==0)
            {
                jud = 1;
                break;
            }
        }
        if(jud==1)
            puts("YES");
        else
            puts("NO");
    }
}

B

给一个n*n的全为白色的方格,现将其染色,又给定四个边框被染成黑色的方格数目,问是否存在满足这种情况的染色方案。

这个B题有点难度了。显然如果每边的染色数小于等于n-2时,一定是成立的,且不会对其他边框产生影响。问题的关键就在于四个角的染色情况,我们可以直接枚举四个角是否染色,也就16种情况。再处理是否染色对给定标准的影响,若染色,则挨着的两条边染色数都减1,最后若四边染色数都小于等于n-2,且大于0,则成立。

#include<bits/stdc++.h>
#define MAXN 200000
using namespace std;
inline int re()
{
    char f=getchar();
    int x=0,k=1;
    while(f>'9'||f<'0')
    {
        if(f=='-') k=-1;
        f=getchar();
    }
    while(f>='0'&&f<='9')
    {
        x=x*10+f-'0';
        f=getchar();
    }
    return x*k;
}

int T,n,u,l,r,d;
bool jud()
{
    if(u<=n-2&&r<=n-2&&l<=n-2&&d<=n-2)
        return 1;
    return 0;
}
int main()
{
    T = re();
    while(T--)
    {
        n = re();
        u = re(), r = re(), d = re(), l = re();
        bool ans_find = 0;
        if(u<=n-2&&r<=n-2&&l<=n-2&&d<=n-2)
            ans_find = 1;
        for (int i = 0; i <= 1;i++)
        {
            for (int j = 0; j <= 1;j++)
            {
                for (int k = 0; k <= 1;k++)
                {
                    for (int f = 0; f <= 1;f++)
                    {
                        int uu = u, rr = r, dd = d,ll = l;
                        if(i)
                            uu--, rr--;
                        if(j)
                            rr--, dd--;
                        if(k)
                            dd--, ll--;
                        if(f)
                            ll--, uu--;
                        if(ll<0||uu<0||rr<0||dd<0)
                            continue;
                        if(uu<=n-2&&rr<=n-2&&ll<=n-2&&dd<=n-2)
                            ans_find = 1;
                    }
                }
            }
        }
        if(ans_find)
            puts("YES");
        else
            puts("NO");
    }
}

C

有 n个箱子,m 个特殊位置,在一条数轴上。你一开始的位置为 0,所有位置都是整数位置,你每次可以向左/右移动一格单位。如果该位置有箱子,你会把该位置的箱子向你前进的方向推一格。如果箱子前进的位置也有箱子,箱子也会推动箱子。问最多有多少个箱子在特殊位置上。

思路还比较好像,但一些细节的代码构造很磨人。显然大于0和小于0的情况几乎等效,我们只需考虑一边。首先记录一个后缀,统计i特殊位置向后,有多少个箱子在位置上。我们可以发现,如果要最大,那我们推动的第一个箱子或者最后一个箱子一定在特殊位置上。我们就可以枚举每一个特殊位置,我是令该位置为最后一个箱子。那我们需要知道在这个位置之前有多少个箱子,这些箱子又覆盖了多少个特殊位置,用lower_bound实现。(如果是为第一个箱子还有考虑推走的箱子占有的格子中是否原本有箱子,很麻烦)。

#include<bits/stdc++.h>
#define MAXN 210000
#define forn(i, n) for (int i = 1; i <= n;i++)
using namespace std;
inline int re()
{
    char f=getchar();
    int x=0,k=1;
    while(f>'9'||f<'0')
    {
        if(f=='-') k=-1;
        f=getchar();
    }
    while(f>='0'&&f<='9')
    {
        x=x*10+f-'0';
        f=getchar();
    }
    return x*k;
}

int T;
map<int,bool> s;
int al[MAXN], ar[MAXN], bl[MAXN], br[MAXN];
int aft[MAXN];
int nl, nr, ml, mr, n, m;
int main()
{
    T = re();
    while(T--)
    {
        nl = nr = ml = mr = 0;
        n = re(), m = re();
        forn(i,n)
        {
            int x = re();
            if(x<0)
                al[++nl] = x*-1;
            else
                ar[++nr] = x;
        }
        forn(i,m)
        {
            int x = re();
            if(x<0)
                bl[++ml] = x*-1;
            else
                br[++mr] = x;
        }
        sort(al + 1, al + nl + 1);
        sort(bl + 1, bl + ml + 1);

        s.clear();
        forn(i,nl)
            s[al[i]] = 1;
        forn(i,ml)
        {
            if(s[bl[i]])
                aft[i] = 1;
            else
                aft[i] = 0;
        }
        aft[ml+1]=0;
        for (int i = ml-1; i >= 1;i--)
            aft[i] += aft[i + 1];
        int ansl = aft[1];
        int j = 0;
        forn(i,ml) //枚举尾坐标
        {
            //i位前有多少个箱子
            int cnt = lower_bound(al + 1, al + nl + 1, bl[i]) - (al + 1);
            //这些箱子占了多少个特殊位置
            int pos = lower_bound(bl + 1, bl + ml + 1, bl[i] - cnt+1) - (bl + 1);
            ansl = max(ansl, aft[i+1] + i - pos);
        }

        s.clear();
        forn(i,nr)
            s[ar[i]] = 1;
        forn(i,mr)
        {
            if(s[br[i]])
                aft[i] = 1;
            else
                aft[i] = 0;
        }
        for (int i = mr-1; i >= 1;i--)
            aft[i] += aft[i + 1];
        aft[mr+1]=0;
        int ansr = aft[1];
        j=0; 
        forn(i,mr) //枚举尾坐标
        {
            //i位前有多少个箱子
            int cnt = lower_bound(ar + 1, ar + nr + 1, br[i]) - (ar + 1);
            //这些箱子占了多少个特殊位置
            int pos = lower_bound(br + 1, br + mr + 1, br[i] - cnt+1) - (br + 1);
            ansr = max(ansr, aft[i+1] + i - pos);
        }
        int ans = ansl + ansr;
//        cout<<ansl<<" "<<ansr<<endl;
        cout << ans << endl;
    }
}

D

给你一颗树,满足有 n 个叶子结点,且每个结点(除了叶子结点)都至少有两个儿子每个结点有权值,满足父结点权值严格大于儿子结点。又给了每两个叶子节点的lca的权值。请将这棵树重构出来。

简单来讲就是,就是将权值从低到高排序,升序依次处理。因为从root到叶,权值是呈一个递减趋势,我们把树从下向上构建。
具体的思路在这里,大佬写的非常好

#include<bits/stdc++.h>
#define MAXN 1100
#define forn(i, n) for (int i = 1; i <= n;i++)
using namespace std;
inline int re()
{
    char f=getchar();
    int x=0,k=1;
    while(f>'9'||f<'0')
    {
        if(f=='-') k=-1;
        f=getchar();
    }
    while(f>='0'&&f<='9')
    {
        x=x*10+f-'0';
        f=getchar();
    }
    return x*k;
}
struct a1{
    int ans,x,y; 
};
bool operator <(a1 x,a1 y){
    if(x.ans==y.ans)
        return x.x>y.x;
    return x.ans>y.ans;
}
int n;
int a[510][510];
int fa[MAXN],upper_fa[MAXN],sal[MAXN];
int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
int main()
{
    n=re();
    priority_queue<a1> q;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            a[i][j]=re();
            if(i<j)
            {
            	a1 tmp;
            	tmp.ans=a[i][j],tmp.x=i,tmp.y=j;
            	q.push(tmp);
			}  
            if(i==j)
                sal[i]=a[i][j];
        }    

    for(int i=1;i<=n*3;i++)
        fa[i]=i;
    
    int cnt=n;
    while(!q.empty())
    {
        a1 u=q.top();q.pop();
        int fax=find(u.x),fay=find(u.y);
//        cout<<u.x<<" "<<u.y<<endl;
        if(fax==fay) continue;
//        cout<<fax<<" "<<fay<<endl;
        if(sal[fax]<u.ans && sal[fay]<u.ans)
        {
            sal[++cnt]=u.ans;
            fa[fax]=cnt,fa[fay]=cnt;
            upper_fa[fax]=cnt,upper_fa[fay]=cnt;
        }
        else if(sal[fax]<u.ans&&sal[fay]==u.ans)
        {
            fa[fax]=fay,upper_fa[fax]=fay;
        }
        else if(sal[fay]<u.ans&&sal[fax]==u.ans)
        {
            fa[fay]=fay,upper_fa[fay]=fax;
        }
        
    }
    
    cout<<cnt<<endl;
    for(int i=1;i<=cnt;i++)
        cout<<sal[i]<<" ";
    cout<<endl<<cnt<<endl;
    for(int i=1;i<cnt;i++)
        cout<<i<<" "<<upper_fa[i]<<endl;
    
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值