Codeforces Round 913 (Div. 3)(D二分 F环加枚举 G基环树)

裂开昨晚差个E ak了,赛后居然又做出来了裂开

A - Rook

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
const long long inf=1e17;
int n,m,k;

void solve()
{
    char a;
    int x;
    cin>>a>>x;
    for(int i=1;i<=8;i++){
        if(i==x) continue;
        cout<<a<<i<<"\n";
    }
    for(char i='a';i<='h';i++){
        if(i==a) continue;
        cout<<i<<x<<"\n";
    }
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

B - YetnotherrokenKeoard

我是直接拿两个栈模拟的,一个放小写一个放大写最后根据位置输出

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<char, int> PII;
const long long inf=1e17;
int n,m,k;
int l[N],r[N];
void solve()
{
    string s;
    cin>>s;
    vector<PII> st1,st2;
    for(int i=0;i<s.size();i++){
        if(s[i]=='b'){
            if(st1.empty()) continue;
            else st1.pop_back();
        }
        else if(s[i]=='B'){
            if(st2.empty()) continue;
            else st2.pop_back();
        }
        else if(islower(s[i])){
            st1.push_back({s[i],i});
        }
        else st2.push_back({s[i],i});
    }
    int idx1=0,idx2=0;
    while(idx1<st1.size()&&idx2<st2.size()){
        if(st1[idx1].second<st2[idx2].second){
            cout<<st1[idx1].first;
            idx1++;
        }
        else{
            cout<<st2[idx2].first;
            idx2++;
        }
    }
    while(idx1<st1.size()){
            cout<<st1[idx1].first;
            idx1++;
    }
    while(idx2<st2.size()){
            cout<<st2[idx2].first;
            idx2++;
    }
    cout<<"\n";
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

C:

直觉题....

我也不知道为啥看了个题就直接觉得跟最大值有关...,可能每天刷一场cf刷多了,直觉就来了....

可以手玩发现如果最大值很大,那么全都去消掉最大值,否则肯定能互相消完,特判奇数

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
const long long inf=1e17;
int n,m,k;
int l[N],r[N];
void solve()
{
    cin>>n;
    string s;
    cin>>s;
    map<char,int> mp;
    for(auto x:s) mp[x]++;
    int mx=0;
    for(auto [k,v]:mp){
        mx=max(mx,v);
    }
    int res=0;
    if(n%2==1) res=1;
    if(n-mx>=mx) mx=0;
    else mx=mx-(n-mx);
    cout<<max(res,mx)<<"\n";
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

D - Jumping Through Segments

对就是这个题,我做了一个小时,然后F+G也才用了一个小时

首先K肯定有单调性可以二分,难点是如何check

我是这样想的他不是每次可以移动0-k距离吗

然后我直接维护一个可达区间,如果当前区间在这个可达区间右侧,那我最右边可以直接拉曼跳到right+k,左区间可以往左边跳,另一个同理

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
const long long inf=1e17;
int n,m,k;
int l[N],r[N];
void solve()
{
    cin>>n;
    l[0]=r[0]=0;
    for(int i=1;i<=n;i++){
        cin>>l[i]>>r[i];
    }
    int res=0;
    auto check=[&](int k)
    {
        int left=0,right=0;
        for(int i=1;i<=n;i++)
        {
            if(r[i]>=right)
            {
                if(right+k>=l[i])
                {
                    left=max(left-k,l[i]);
                    right=min(right+k,r[i]);
                }
                else return false;
            }
            else
            {
                if(left-k<=r[i])
                {
                    left=max(left-k,l[i]);
                    right=min(right+k,r[i]);
                }else return false;

            }
        }
        return true;
    };
    int ll=0,rr=1e9;
    while(ll<rr){
        int mid=ll+rr>>1;
        if(check(mid)) rr=mid;
        else ll=mid+1;
    }
    cout<<ll<<"\n";

   // cout<<res<<"\n";
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

E - Good Triples

可以发现每一位是独立的,然后n最多7位

直接枚举a b c是哪些数即可,然后乘法原理

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
const long long inf=1e17;
int n,m,k;
int a[N];
string s;
int res=0;

void solve()
{
    cin>>n;
    int res=0;
    s=to_string(n);n=s.size();
    for(int i=0;i<n;i++)
    {
        int cnt=0;
        for(int a=0;a<=9;a++){
            for(int b=0;b<=9;b++){
                for(int k=0;k<=9;k++){
                    if(a+b+k==(s[i]-'0')) cnt++;
                }
            }
        }
        if(res==0) res=cnt;
        else res*=cnt;
    }
    
    cout<<res<<"\n";
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

F - Shift and Reverse

首先手完题老规矩

先想操作有啥性质

对于第一个操作等于整体区间往右移动 (如果先翻转则变成向左移动)

第二个操作就是可以让整个递减区间变成递增

然后我们直接拉环成链

如果存在一个区间长度为n那么就是可以通过右移变成一个递增或者递减的序列

然后计算次数即可

我get函数里面 f维护的就是递增连续个数,g是递减连续

然后枚举向左移动还是向右移动,分别计算递增和递减所需要的最小次数即可

然后因为可以翻转,我们可以直接把整个数组翻转再求一编减少代码量

计算次数的话就交给读者自己画图算咯

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
const long long inf=1e17;
int n,m,k;
int a[N];
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    
    int res=2e18;
    auto get=[&](int v){
            vector<int> f(n*2+10);
            for(int i=1;i<=n;i++)
            {
                if(a[i]>=a[i-1]) f[i]=f[i-1]+1;
                else f[i]=1;
            }
            if(f[n]==n){
                res=min(res,v+0ll);
            }
            for(int i=n+1;i<=n+n;i++)
            {
                a[i]=a[i-n];
                if(a[i]>=a[i-1]) f[i]=f[i-1]+1;
                else f[i]=1;
                if(f[i]==n)
                {
                    res=min(res,v+n-(i-n));    
                }
            }
            vector<int> g(n*2+10);
            g[1]=1;
            for(int i=2;i<=n;i++){
                if(a[i-1]>=a[i]) g[i]=g[i-1]+1;
                else g[i]=1;
            }
            if(g[n]==n){
                res=min(res,v+1ll);
            }
            for(int i=n+1;i<=n+n;i++){
                if(a[i-1]>=a[i]) g[i]=g[i-1]+1;
                else g[i]=1;
                if(g[i]==n) res=min(res,v+1+n-(i-n));
            }
    };
    get(0);
    reverse(a+1,a+1+n);
    get(1);
    if(res==2e18) res=-1;
    cout<<res<<"\n";
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

G - Lights

正常套路题

n点n边,这是一个基环树

然后我习惯两个算法

1.建立反向边,然后直接从环开始dfs,

2.正常建边,拓扑排序删掉叶子节点,留下环,再单独处理环

因为要顺便记录操作所以我选的是2

然后拓扑排序剩下一些环

然后问题变成环里面求最小次数

正常是套路是随便选一个点dp当前点选还是不选

但是注意到,如果当前点是亮的,一定要改变他,所以我们直接贪心即可

所以我们直接枚举当前点改变或者不改变即可

我的dfs函数是记录原本这个环每个点的拓扑排序后的灯状态

因为这两个枚举都要用到原本灯状态,所以我直接懒狗,写了个dfs函数来记录到map里面了

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
const long long inf=1e17;
int n,m,k;
int a[N];
vector<int> g[N];
void solve()
{
    cin>>n;
    string s;cin>>s;
    s="?"+s;
    for(int i=1;i<=n;i++) g[i].clear();
    vector<int> d(n+10);
    for(int i=1;i<=n;i++){
        int x;cin>>x;
        if(s[i]=='1') a[i]=1;
        else a[i]=0;
        g[i].push_back(x);
        d[x]++;
    }
    vector<int> res;
    queue<PII> q;
    for(int i=1;i<=n;i++)
        if(d[i]==0)
        {
            if(a[i]==1)
            {
                res.push_back(i);
                a[i]=0;
                q.emplace(i,1);
            }
            else q.emplace(i,0);
        }
    
    vector<bool> st(n+10);
    while(q.size()){
        auto t=q.front();
        q.pop();
        st[t.first]=true;
        for(auto v:g[t.first])
        {
            a[v]^=t.second;
            if(--d[v]==0)
            {
                if(a[v]==0) q.emplace(v,0);
                else
                {
                    res.push_back(v);
                    q.emplace(v,1);
                }
                a[v]=0;
            }
        }
    }
map<int,int> mp;
    function<void(int)> dfs=[&](int u){
        if(st[u]) return ;
        mp[u]=a[u];
        st[u]=true;
        for(auto v:g[u]) dfs(v);
        st[u]=false;
    };
    for(int i=1;i<=n;i++){
        if(st[i]) continue;
        vector<int> d1,d2;
        mp.clear();
        int u=i;
        dfs(u);
        d1.push_back(u);
        mp[u]^=1;mp[g[u][0]]^=1;
        u=g[u][0];
        while(u!=i)
        {
            if(mp[u]){
                d1.push_back(u);
                mp[u]^=1;
                mp[g[u][0]]^=1;
            }
            u=g[u][0];
        }
        if(mp[u]==1){
            cout<<-1<<"\n";return ;
        }
        mp.clear();
        dfs(u);
        u=g[u][0];
        st[i]=true;
        while(u!=i)
        {
            st[u]=true;
            if(mp[u])
            {
                d2.push_back(u);
                mp[u]^=1;
                mp[g[u][0]]^=1;
            }
            u=g[u][0];
        }
        if(mp[i]==1){
            cout<<"-1\n";return ;
        }
        if(d1.size()>d2.size()) swap(d1,d2);
        for(auto x:d1) res.push_back(x);
    }
    cout<<res.size()<<"\n";
    for(auto x:res) cout<<x<<" ";
    cout<<"\n";
    
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值