Educational Codeforces Round 168 (Rated for Div. 2) A~E

本期封面原图 制图redman
这场Div2难度绝对不对劲吧 D题5000人过?

A - Strong Password

题意

在字符串内加一个字符使得他的强度最高 强度的定义是每次出现和上一个字符不同的字符可以加一

思路

所以就在原本相同的里面插一个不同的字符 找不到就直接丢在最后面

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

void solve()
{
    string s;
    cin>>s;
    s=' '+s;
    int n=s.size();
    int flag=0;
    for(int i=0;i<n;i++)
    {
        if(i>0)
            printf("%c",s[i]);
        if(s[i]==s[i+1] and flag==0)
        {
            flag=1;
            char now=s[i];
            now++;
            if(now>'z')
                now='a';
            printf("%c",now);
        }
    }
    if(flag==0)
    {
        char now=s[n-1];
        now++;
        if(now>'z')
            now='a';
        printf("%c",now);
    }
    printf("\n");
}

int main()
{
    int T=1;
    scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

B - Make Three Regions

题意

在一个最多只有1个联通块的地图里能找到多少个格子使得将其变为阻碍方块刚好能形成3个联通块

思路

特别注意题目说了原本最多只有一个联通块 所以其实只需要找

X.X          ...
...          X.X

这两种情况就可以了 没有其他情况能让我的联通块刚好变成三个

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
int n;
string s[2];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};

void solve()
{
    scanf("%d",&n);
    cin>>s[0]>>s[1];
    int cnt=0;
    for(int i=0;i<n;i++)
    {
        if(s[0][i]=='.' and s[1][i]=='.')
        {
            if(i>0 and i<n-1)
            {
                if(s[0][i-1]=='.' and s[0][i+1]=='.')
                {
                    if(s[1][i-1]=='x' and s[1][i+1]=='x')
                    {
                        cnt++;
                    }
                }
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        if(s[0][i]=='.' and s[1][i]=='.')
        {
            if(i>0 and i<n-1)
            {
                if(s[1][i-1]=='.' and s[1][i+1]=='.')
                {
                    if(s[0][i-1]=='x' and s[0][i+1]=='x')
                    {
                        cnt++;
                    }
                }
            }
        }
    }
    printf("%d\n",cnt);
}

int main()
{
    int T=1;
    scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

C - Even Positions

题意

定义一个括号序列的强度是每一对匹配上的括号之间距离的和 现在序列奇数位的字符全都不知道 要你最大化这个序列的长度

思路

因为是只有奇数位被抠掉 所以最后一个肯定是右括号 所以要优先把左括号安顿好 所有的左括号我们都先在他右边一格直接放一个右括号 然后右括号再往前找最近的空格位置

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

void solve()
{
    int n;
    scanf("%d",&n);
    string s;
    cin>>s;
    ll ans=0;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='(')
        {
            ans++;
            s[i+1]=']';
        }
    }
//    cout<<s<<endl;
    for(int i=n-1;i>0;i--)
    {
        if(s[i]==')')
        {
            int j=i-1;
            while(s[j]!='_')
                j--;
            ans+=i-j;
            s[j]='[';
        }
    }
//    cout<<s<<endl;
    printf("%lld\n",ans);
}

int main()
{
    int T=1;
    scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

D - Maximize the Root

题意

给一棵树 每次可以选择任意节点将他所有子孙的权值减一 他自己加一 操作任意次使得树的根节点的权值最大

思路

每次让根节点变大 下面的所有节点都要减一 所以影响最大值的就只有根节点子孙的最小权值节点 找到他 想办法让他变大 那么与上面同理 我们需要找到他的子孙中的最小权值节点 然后两个人平均一下
综上所述 我们要进行的是一个dfs递归的过程

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int N=200050;
int n;
int a[N];
int p[N];
vector<int> e[N];
int dfs(int now)
{
    if(e[now].size()==0 and now!=1)
    {
        return a[now];
    }
    int m=1e9+7;
    for(int i:e[now])
    {
        int tmp=dfs(i);
        m=min(m,tmp);
    }
    if(now==1)
        return m+a[1];
    if(a[now]>m)
        return m;
    return (a[now]+m)/2;
}

void solve()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&p[i]);
        e[p[i]].push_back(i);
    }
    int ans=dfs(1);
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)
    {
        e[i].clear();
    }
}

int main()
{
    int T=1;
    scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

E - Level Up

题意

k个经验升一级 等级严格大于怪物时怪物会逃跑 所以不会累计经验 每个怪物的等级告诉你 进行q次查询 每次问当k为给定值时能不能跟第i个怪物打起来 打起来输出YES

复盘

一开始想的是4秒感觉直接写简单优化下就能过 然后写的是这么个带记忆上下界的优化但是WA5了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll n,q;
const int N=200050;
ll a[N];
ll prel[N],prer[N];
bool check(ll i,ll x)
{
    int cnt=0;
    int lv=1;
    for(int j=1;j<i;j++)
    {
        if(a[j]<lv)
            continue;
        cnt++;
        if(cnt==x)
        {
            cnt=0;
            lv++;
        }
    }
    if(a[i]<lv)
        return false;
    return true;
}

void solve()
{
    scanf("%lld%lld",&n,&q);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    memset(prel,0,sizeof(prel));
    memset(prer,n+1,sizeof(prer));
    while(q--)
    {
        ll i,x;
        scanf("%lld%lld",&i,&x);
        if(prer[i]<=x)
        {
            printf("YES\n");
            continue;
        }
        else if(prel[i]>=x)
        {
            printf("NO\n");
            continue;
        }
        bool now=check(i,x);
        if(now)
        {
            printf("YES\n");
            prer[i]=x;
        }
        else
        {
            printf("NO\n");
            prel[i]=x;
        }
    }
}

int main()
{
    int T=1;
    //scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

思路

那回过头来还是要老老实实预处理答案 对于每个怪兽都预处理一个最小的k保证这个k能够让我打这个怪兽 k的查找肯定是二分 但是现在已经是O(nlogn)了 如果我的check函数又是从头扫肯定不行 比刚才那个还慢 我们注意到其实需要的是前面的k的个数 所以我们可以用高级数据结构维护前面k的个数 可以用主席树 但是一看这个数据范围只有2e5 那干脆直接用树状数组维护一个桶就行了

代码

#include <bits/stdc++.h>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int N=200050;
int n;
int a[N],tr[N];
int p[N];
void add(int x,int y)
{
    for(;x<=n;x+=lowbit(x))
    {
        tr[x]+=y;
    }
}
int query(int x)
{
    int res=0;
    for(;x;x-=lowbit(x))
    {
        res+=tr[x];
    }
    return res;
}
bool check(int k,int i)
{
    int sum=query(k);
    int now=1+sum/k;
    return now<=a[i];
}

void solve()
{
    int q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    memset(tr,0,sizeof(tr));
    for(int i=1;i<=n;i++)
    {
        int l=1,r=n;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(check(mid,i))
            {
                r=mid;
            }
            else
            {
                l=mid+1;
            }
        }
        p[i]=l;
        add(p[i],1);
    }
    while(q--)
    {
        int i,x;
        scanf("%d%d",&i,&x);
        if(p[i]<=x)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
}

int main()
{
    int T=1;
    //scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}
  • 20
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值