Codeforces Round 849 Div. 4 题解

对Niko的崇拜并不能使我顺利做出G2题😢


A. Codeforces Checking

题面

注意别漏字母就行.

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define lowbit(x) ((x)&-(x))
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        char c;
        cin>>c;
        if(c=='c'||c=='o'||c=='d'||c=='e'||c=='f'||c=='r'||c=='s')
            cout<<"YES"<<'\n';
        else
            cout<<"NO"<<'\n';
    }
    return 0;
}

B. Following Directions

题面

把题意翻译一下即可.

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define lowbit(x) ((x)&-(x))
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        string s;
        cin>>s;
        int x=0,y=0;
        bool flag=false;
        for(int i=0;i<n;i++)
        {
            if(s[i]=='L')
                x--;
            else if(s[i]=='R')
                x++;
            else if(s[i]=='U')
                y++;
            else if(s[i]=='D')
                y--;
            if(x==1&&y==1)
            {
                cout<<"YES"<<'\n';
                flag=true;
                break;
            }
        }
        if(!flag)
            cout<<"NO"<<'\n';
    }
    return 0;
}

C. Prepend and Append

题面

明显操作可以回溯回去.

只需从最终的二进制串往回推,推到不能动了就是最短初始串.

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define lowbit(x) ((x)&-(x))
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        string s;
        cin>>s;
        int len=s.length();
        int i=0,j=len-1;
        while(i<=j)
        {
            if((s[i]=='0'&&s[j]=='1')||(s[i]=='1'&&s[j]=='0'))
                len-=2;
            else
                break;
            i++,j--;
        }
        cout<<len<<'\n';
    }
    return 0;
}

D. Distinct Split

题面

需要注意的是分成的两个子串各自连续,所以不能直接 .

先遍历一遍原字符串获得每个字母出现次数,用map记录.

注意到如果字符串 的子串,那么 .

所以两个子串是原子串的一个划分时是更优的.

只需要枚举中间断点的位置,有 个位置.

断点向右移动时,同时更新左右子串的 ,可以 的时间复杂度内完成(不是 是因为小写字母只有26种).

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define lowbit(x) ((x)&-(x))
map<char,int>mp,mp1;
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        string s;
        cin>>s;
        mp.clear(),mp1.clear();
        for(int i=0;i<s.length();i++)
        {
            mp[s[i]]++;
        }
        int ans=0;
        for(int i=0;i<s.length();i++)
        {
            mp1[s[i]]++;
            mp[s[i]]--;
            int an=0;
            for(auto it=mp.begin();it!=mp.end();it++)
                an+=min(1,it->second);
            for(auto it=mp1.begin();it!=mp1.end();it++)
                an+=min(1,it->second);
            ans=max(an,ans);
        }
        cout<<ans<<'\n';
    }
    return 0;
}

E. Negatives and Positives

题面

将相邻两个数置为相反数的操作可以做无数次,可以想到将两个数拓展为一串数,都进行一遍题中的操作,那么这一串数的中间的数都改变了两次符号(相当于没变号),只有两端变号.

操作可以等效为在 中任选两个数将它们的符号取反.

题目要求将 最大,所以将尽可能多的数变为正数,剩下变不了的一定要绝对值最小,使得对和的影响最小.

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define lowbit(x) ((x)&-(x))
const int N=2e5+5;
int a[N];
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        int m=1e9+5;
        int cnt=0;
        ll sum=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            sum+=labs(a[i]);
            m=min(m,abs(a[i]));
            if(a[i]<0)
                cnt++;
        }
        if(cnt%2==0)
            cout<<sum<<'\n';
        else
            cout<<sum-2*m<<'\n';
    }
    return 0;
}

F. Range Update Point Query

题面

发现并不需要每操作一次就将 都更新,可以先打上 标记(记录操作次数),等需要的时候再计算.

用差分替代区间修改可以大大提高效率.

同时还有时不时的查询(求前缀和),所以可以用树状数组存储 数组.

因为求数位和收敛很快,所以对 数组甚至不用用一次更新一次.

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lowbit(x) ((x)&-(x))
const int N=2e5+5;
int a[N];
int dif[N];
void update(int x,int d,int n)
{
    while(x<=n)
    {
        dif[x]+=d;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int ans=0;
    while(x>0)
    {
        ans+=dif[x];
        x-=lowbit(x);
    }
    return ans;
}
int getnum(int x)
{
    int ans=0;
    while(x)
    {
        ans+=x%10;
        x/=10;
    }
    return ans;
}
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int n,q;
        cin>>n>>q;
        memset(dif,0,sizeof(dif));
        for(int i=1;i<=n;i++)
            cin>>a[i];
        for(int i=1;i<=q;i++)
        {
            int op;
            cin>>op;
            if(op==1)
            {
                int l,r;
                cin>>l>>r;
                update(l,1,n);
                update(r+1,-1,n);
            }
            else if(op==2)
            {
                int x;
                cin>>x;
                int lazy=sum(x);
                int ans=a[x];
                while(lazy--)
                {
                    ans=getnum(ans);
                    if(ans<10)
                        break;
                }
                cout<<ans<<'\n';
            }
        }
    }
    return 0;
}

G1. Teleporters (Easy Version)

题面

可以发现最优的方法下人不会在数轴上闲逛,都是从0坐标直奔目的地然后传送回0坐标.

所以只需要更新权值之后排个序,计算一下元素和即可.

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define lowbit(x) ((x)&-(x))
const int N=2e5+5;
priority_queue<int,vector<int>,greater<int>> s;
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int n,c;
        cin>>n>>c;
        while(!s.empty())
            s.pop();
        int a;
        for(int i=1;i<=n;i++)
        {
            cin>>a;
            s.push(a+i);
        }
        int ans=0;
        int cnt=0;
        while(!s.empty()&&ans+s.top()<=c)
        {
            ans+=s.top();
            s.pop();
            cnt++;
        }
        cout<<cnt<<'\n';
    }
    return 0;
}

G2. Teleporters (Hard Version)

题面

留坑.

一开始以为成环后跟G1一样,后来发现第一步只能从0开始没有对称性.

解决了第一步似乎就可以了?

看了题解,仿着题解码了一份代码.

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define lowbit(x) ((x)&-(x))
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        int n,c;
        cin>>n>>c;
        vector<pair<ll,ll>> a;
        for(int i=1;i<=n;i++)
        {
            int x;
            cin>>x;
            a.push_back({x+min(i,n+1-i),x+i});
        }
        sort(a.begin(),a.end());
        vector<ll> pref;
        pref.push_back(0);
        for(int i=0;i<n;i++)
        {
            pref.push_back(pref.back()+a[i].first);
        }
        int ans=0;
        for(int i=0;i<n;i++)
        {
            int new_c=c-a[i].second;
            int l=0,r=n;
            int mx=0;
            while(l<=r)
            {
                int mid=l+r>>1;
                ll price=pref[mid];
                int now=mid+1;
                if(mid>i)
                {
                    price-=a[i].first;
                    now--;
                }
                if(price<=new_c)
                {
                    mx=max(now,mx);
                    l=mid+1;
                }
                else
                    r=mid-1;
            }
            ans=max(ans,mx);
        }
        cout<<ans<<'\n';
    }
    return 0;
}

img_show