Educational Codeforces Round 132 (Rated for Div. 2)

 终榜:

Educational Codeforces Round 132 (Rated for Div. 2)_第1张图片

 

A:

题目:

有三扇门和其中一个门的钥匙,每个门后面可能有其他门的钥匙,问能否将三扇门全部打开

思路:

暴力即可

#include
using namespace std;
#define ll long long
#define T()\
	int tt; \
	cin>>tt; \
	while(tt--)
#define endl "\n"
const int N=105;
int a[N];
int main()
{
    T()
    {
        int x;
        cin>>x;
        for(int i=1;i<=3;i++)cin>>a[i];
        int ct=1;
        while(a[x])//如果当前的钥匙还能继续开门
        {
            ct++;
            x=a[x];
        }
        if(ct==3)puts("YES");//如果开了三扇门
        else puts("NO");
    }
}

B:

题目:

给定n座山的高度以及m次询问

每次询问给定一个l和r(l有可能大于r)

每次你从坐标为 l 的山出发到达坐标为 r 的山,如果你路径上的下一座山比当前山高的话不耗费体力,否则耗费 高度差 的体力,问每次耗费多少

思路:做一个简单的预处理即可

#include
using namespace std;
#define ll long long
#define T()\
	int tt; \
	cin>>tt; \
	while(tt--)
#define endl "\n"
const ll mod=1e9+7;
const int N=2e6+10;
ll a[N];
ll cnt1[N],cnt2[N];
int main()
{
    // T()
    {
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=2;i<=n;i++)
        {
            if(a[i]>=a[i-1])cnt1[i]=cnt1[i-1];//预处理从前到后的山
            else cnt1[i]=cnt1[i-1]+(a[i-1]-a[i]);
        }
        cnt2[n]=0;
        for(int i=n-1;i>=1;i--)
        {
            if(a[i]>=a[i+1])cnt2[i]=cnt2[i+1];//预处理从后到前的山
            else cnt2[i]=cnt2[i+1]+(a[i+1]-a[i]);
        }
        while(m--)
        {
            int l,r;
            cin>>l>>r;
            if(l<=r)
            {
                cout<

C:

题目:

给定一个字符串,里面含有 '('  ,  ')'  ,  '?'三种字符,‘?’可以变成任意的括号(左括号或右括号),问组成合法括号序列的方法是否唯一,

如果唯一打印“YES”,否则打印“NO”,题目保证数据一定有一组解

合法括号定义:设‘(’的数量为a,‘)’的数量为b,对于任意的i,都有a>=b。

思路:

我们可以发现,如果当前序列中 ‘ (’的数量已经为总长度(下面设为 L )的一半了,那么解法一定唯一,如果没有满足上述条件,那么对于前面某些个左括号,若解法唯一,他们一定是‘(’,下面给出证明。

证:对于‘(’数量不到 L /2 时,对于第一个‘?’,我们可以知道这个字符为‘(’时序列一定合法,因为这样可以尽最大可能满足合法括号定义,因此如果这个括号为‘)’时序列也合法,那么一定是多解,输出“NO”。

那么我们如何判断括号为‘)’时也合法呢?

我们只需要将前面的(L/2-a)个问号赋值成‘(’,并且把剩下的括号赋值成‘)’,然后我们交换最后一个通过‘?’转换成的左括号以及第一个通过‘?’转换成的右括号的位置,判断序列是否合法即可,如果合法,说明有多解,不然就是唯一解。

#include
using namespace std;
#define ll long long
#define T()\
	int tt; \
	cin>>tt; \
	while(tt--)
#define endl "\n"
const int N=2e6+10;
int main()
{
    T()
    {
        string s;
        cin>>s;
        int now=0;
        for(int i=0;ipos;
        for(int i=0;i

D:

题目:

给定一个n行m列的地图,接下来给定m个数,对于1<=i<=m,hi表示第m列的前hi行格子被堵塞,不能通过,即(1,m)~(hi,m)这hi个格子不能通过。

现给定Q次询问,每次询问给定一个起始坐标(qx,qy)以及终止坐标(zx,zy)以及一个k,

一个机器人从起始坐标出发前往终止坐标,可以走任意次,每次走的格子数量规定为k,并且是朝着同一个方向走k步,规定机器人不能走到地图外面,也不能通过被堵塞的格子,问能否到达目的地。(给定的起始坐标以及终止坐标没有被堵塞)

数据范围:1<=n<=1e9,1<=m<=2e5,0<=hi<=n,1<=Q<=2e5

思路:

通过线段树维护一个区间最大值(当然,ST表也行),我们可以让机器人每次都先走到当前列的尽可能靠后的一行(假设是sj),然后走到终止坐标的列,然后前往终止坐标的行,只要起始坐标的列到终止目标的列之间没有被堵塞即可到达,所以我们查询这段区间的最值,然后和sj比较即可,需要注意的是,由于题目中规定每次走的格子数量必须为k,所以有:

abs(qx-zx)%k==0&&abs(qy-zy)==0 

#include
using namespace std;
#define ll long long
#define T()\
	int tt; \
	cin>>tt; \
	while(tt--)
#define endl "\n"
const int N=2e6+10;
ll a[N];
struct node
{
    ll l,r,val;
}tr[N<<2];
void build(int now,int l,int r)//建树
{
    tr[now].l=l,tr[now].r=r;
    if(l==r)
    {
        tr[now].val=a[l];
        return;
    }
    int mid=l+r>>1;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    tr[now].val=max(tr[now<<1].val,tr[now<<1|1].val);
}
ll query(int now,int l,int r,int L,int R)//询问
{
    if(L<=l&&r<=R)return tr[now].val;
    ll ans=0;
    int mid=l+r>>1;
    if(mid>=L)ans=max(ans,query(now<<1,l,mid,L,R));
    if(midzy)//保证起始坐标的列在终止坐标的列的前面
            {
                swap(qx,zx);
                swap(qy,zy);
            }
            if(abs(zx-qx)%k!=0||abs(zy-qy)%k!=0)
            {
                puts("NO");
                continue;
            }
            ll sj=qx+(n-qx)/k*k;//计算sj
            ll zz=query(1,1,m,qy,zy);//查询区间[qy,zy]的最大值
            if(zz>=sj)
            {
                puts("NO");
                continue;
            }
            else puts("YES");
        }
    }
}

你可能感兴趣的:(算法,c++,开发语言)