IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Codeforces Round #789 (Div. 2) A B1 B2 C D E -> 正文阅读

[C++知识库]Codeforces Round #789 (Div. 2) A B1 B2 C D E

Codeforces Round #789 (Div. 2) A B1 B2 C D E

A.Tokitsukaze and All Zero Sequence

题意: 给你一个长度为 n n n a a a数组,你每次操作可以进行下述两种操作的任意一种,求最小操作数使 a a a数组所有数变成 0 0 0

  • 如果 2 2 2个数相同,可以使其中一个数变成 0 0 0
  • 设两个数为 a a a b b b,可以使其中一个数变成 m i n ( a , b ) min(a,b) min(a,b)

思路: 分类讨论,如果存在 0 0 0,那么最小操作数即 0 0 0的个数。 如果不存在 0 0 0,并且存在相同数那么最小操作数即所有数的个数,因为可以通过 1 1 1次操作将 1 1 1个数变成 0 0 0。否则我们需要再多 1 1 1次操作,先将 2 2 2个数变成相同数。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
void cf(){
    int n;
    cin>>n;
    map<int,int>mp;
    bool ok =false;
    bool ok2=false;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        if(x==0)ok=true;
        mp[x]++;
        if(mp[x]>1)ok2=true;
    }
    if(ok){
        int res=0;
        for(auto x:mp){
            if(x.first!=0)res+=x.second;
        }
        cout<<res<<endl;
        return ;
    }
    int res=0;
    for(auto x:mp){
        res+=x.second;
    }
    if(!ok2)res++;
    cout<<res<<endl;
    return ;
} 
signed main(){
    // freopen("input.txt","r",stdin);
	// freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        cf();
    }
}

B1.Tokitsukaze and Good 01-String (easy version)

题意: 给定偶数长度的字符串,其中包含多组由仅由 0 0 0 1 1 1组成的字符串,我们每次操作可以使其中一个 1 1 1变成 0 0 0或者 0 0 0变成 1 1 1。问最小的操作次数使得每组由单一 0 0 0 1 1 1组成的字符串长度皆为偶数。

思路: 因为要求每组长度皆为偶数,那么如果将字符串中的字符 2 2 2 2 2 2个分组,意味着每组中的 2 2 2个字符必须为同一类型,所以如果 2 2 2个字符不是同一类型操作次数就要 + 1 +1 +1

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
void cf(){
    int n;
    cin>>n;
    string s;
    cin>>s;
    int res=0;
    for(int i=0;i<s.size();i+=2){
        res+=(s[i]!=s[i+1]?1:0);
    }
    cout<<res<<endl;
} 
signed main(){
    // freopen("input.txt","r",stdin);
	// freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        cf();
    }
}

B2.Tokitsukaze and Good 01-String (hard version)

题意:B1基础上,额外要求输出最小操作前提下,最少组的数量。

思路: 首先观察字符串中 01 01 01 10 10 10变化对整体的影响, 01 01 01 10 10 10皆可以通过 1 1 1次操作变成 11 11 11 00 00 00的形式,这说明不管其左边或右边是什么字符, 10 10 10 01 01 01形式的子串皆可以通过一次操作完美的与左边或右边的字符融为一体,换句话说就是隐身掉了。那么问题自然就转变成了统计删去 01 01 01 10 10 10之后,有多少组连续 0 0 0和连续 1 1 1子串。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5+10;
bool st[N];
void cf(){
    int n;
    cin>>n;
    string s;
    cin>>s;
    for(int i=0;i<s.size();i++)st[i]=false;
    int a,b;
    a=b=0;
    for(int i=0;i<s.size();i+=2){
        if(s[i]!=s[i+1]){
            a++;
            st[i]=st[i+1]=true;
        }
    }
    int pre=-1;
    for(int i=0;i<s.size();i++){
        if(!st[i]){
            if(pre==-1){
                b++;
                pre=s[i]-'0';
            }
            else if(pre!=s[i]-'0'){
                b++;
                pre=s[i]-'0';
            }
        }
    }
    if(pre==-1)b++;
    cout<<a<<' '<<b<<endl;
    return ;
} 
signed main(){
    // freopen("input.txt","r",stdin);
	// freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        cf();
    }
}

C.Tokitsukaze and Strange Inequality

题意: 给定一个长度不超过 5000 5000 5000的排列数组 p p p,统计其中有多少个四元组 [ a , b , c , d ] [a,b,c,d] [a,b,c,d]满足 a < b < c < d a<b<c<d a<b<c<d p [ c ] > p [ a ] 且 p [ b ] > p [ d ] p[c]>p[a]且p[b]>p[d] p[c]>p[a]p[b]>p[d]

思路: 看到 5000 5000 5000我们会往 O ( n 2 ) O(n^2) O(n2)复杂度的实现方法上去思考,观察后发现我们可以枚举 b b b c c c的位置,因为一旦 b b b c c c的位置确定下来,我们就可以确定查找范围,即在 1 1 1 ~ b ? 1 b-1 b?1的区间内找比 p [ c ] p[c] p[c]小的数量,在 c + 1 c+1 c+1 ~ n n n的区间内找比 p [ b ] p[b] p[b]小的数量。但是我们已经用了 O ( n 2 ) O(n^2) O(n2)复杂度了,显然里面剩下的查询操作 O ( 1 ) O(1) O(1)比较合理,此时就要先将查询的资料预处理。开一个 p r e [ 5000 ] [ 5000 ] pre[5000][5000] pre[5000][5000]的数组用 O ( n 2 ) O(n^2) O(n2)的时间复杂度创建,第 1 1 1维表示当前枚举到的位置,第 2 2 2维表示 1 1 1一个数,即 p r e [ 5 ] [ 8 ] pre[5][8] pre[5][8]表示的含义是前面 5 5 5个数中比 8 8 8小的数的个数,预处理完 O ( 1 ) O(1) O(1)查询既可以解决该题。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5010;
int pre[N][N];
int a[N];
void cf(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)pre[i][j]=0;
    for(int i=1;i<=n;i++){//预处理
        for(int j=1;j<=n;j++){//小于等于j的前i个数
            pre[i][j]=pre[i-1][j];
        }
        for(int j=a[i];j<=n;j++)pre[i][j]++;
    }
    int res=0;
    for(int b=2;b<=n-2;b++)//查询统计
        for(int c=b+1;c<=n-1;c++){
            res+=pre[b-1][a[c]-1]*(pre[n][a[b]]-pre[c][a[b]]);
        }
    cout<<res<<endl;
} 
signed main(){
    // freopen("input.txt","r",stdin);
	// freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        cf();
    }
}

D.Tokitsukaze and Meeting

题意: 现在 n ? m n*m n?m 名学生将按以下方式就坐:

  • 每一轮,所有学生坐到右侧的座位(最后一列的坐到下一行第一列),空出第一行第一列,当前学生在第一行第一列就坐。每个学生可能是 1 1 1或者是 0 0 0,一旦一列中拥有一个学生是 1 1 1或者一列中拥有一个学生是 0 0 0,那么认为该列或该行是好的。统计每当进入一个学生之后,实时好的行和列的总和。

思路: 将行和列拆开来讨论,首先看列: 在纸上画图,每当进入一个新学生,老学生的移动情况为从 1 1 1 ~ n ? 1 n-1 n?1 列移动到 2 2 2 ~ n n n列,这给我们一个信息,所有 c o l [ i col[i col[i% m ] 、 m]、 m] c o l [ ( i + m ) col[(i+m) col[(i+m)% m ] . . . c o l [ ( i + k ? m ) m]...col[(i+k*m) m]...col[(i+k?m)% m ] m] m]始终在一根线上也就是一列上,不管后面加了多少新学生。所以如果 c o l [ i col[i col[i% m ] m] m]的值是 1 1 1,那么后面出现的同在这根线上的学生值一定是 1 1 1,即学生 i + m 、 i + 2 ? m . . . i+m、i+2*m... i+mi+2?m...再次看行: 每新增 m m m 名学生,所有学生的位置下移一行,所以行的贡献将增加以下的数值:这 m m m 名学生将占据第一行,若其中有 1 1 1 ,则带来 1 的贡献。否则没有额外贡献。提前计算好前缀和,就能 O ( 1 ) O(1) O(1) 地求出它有没有带来新的贡献。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
void cf(){
    int n,m;
    cin>>n>>m;
    string s;
    cin>>s;
    vector<int>pre(n*m,0);
    //计算列
    vector<int>a(n*m,0);
    vector<int>col(m,0);
    int ti=0;
    for(int i=0;i<n*m;i++){
        int x=s[i]-'0';
        if(x==1&&!col[i%m]){
            col[i%m]=1;
            ti++;
        }
        a[i]=ti;
    }
    //计算行
    pre[0]=0;
    for(int i=1;i<s.size();i++){
        pre[i]+=pre[i-1]+s[i]-'0';
    }
    ti=0;
    for(int i=0;i<m;i++){
        ti|=s[i]-'0';
        int can=ti;
        a[i]+=ti;
        for(int j=i+m;j<n*m;j+=m){
            if(pre[j]-pre[j-m]>0)can++;
            a[j]+=can;
        }
    }
    for(auto x:a)cout<<x<<' ';
    cout<<endl;
    return ;
} 
signed main(){
    // freopen("input.txt","r",stdin);
	// freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        cf();
    }
}

E.Tokitsukaze and Two Colorful Tapes

题意: 给定两个排列 a a a b b b,自由将 1 1 1~ n n n的排列数填充到 a , b a,b ab之中要求满足同一数必须填补到 a , b a,b a,b的同色块中。求最大的 ∑ i = 1 n a b s ( a i ? b i ) \sum\limits_{i=1}^nabs(a_i-b_i) i=1n?abs(ai??bi?)

思路: 感觉和上一场的 C C C很像,导致理解起来不是很难,本质还是找环,统计每个环的长度 / 2 /2 /2的和,然后每组剩余最大最小分配即可。因为如果奇数情况,最多只有 / 2 /2 /2组可以配对。感觉不是讲的很清楚, 这个构造在本上画下图其实相对会比较好理解。找环的话我还是和上次一样做法,并查集也可,我用的是映射搜索。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+10;
int a[N],b[N];
int aa[N];
bool ok[N];
int len;
void cf(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)ok[i]=false;
    for(int i=1;i<=n;i++)cin>>a[i],aa[a[i]]=i;
    for(int i=1;i<=n;i++)cin>>b[i];
    int res=0;
    for(int i=1;i<=n;i++){
        if(a[i]!=b[i]&&!ok[i]){
            len=1;
            ok[i]=true;
            int j=b[i];
            while(j!=a[i]){
                int idx=aa[j];
                ok[idx]=true;
                len++;
                j=b[idx];
            }
            res+=len/2;
        }
    }
    int sum=0;
    for(int i=1,j=n;i<=res;i++,j--){
        sum+=(j-i)*2;
    }
    cout<<sum<<endl;
} 
signed main(){
    // freopen("input.txt","r",stdin);
	// freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        cf();
    }
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-12 16:18:51  更:2022-05-12 16:19:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/10 15:22:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码