CF-Round599总结

Codeforces Round #599 (Div. 2)

A:Maximum Square
题意:
给出n个柱子高度,问柱子可以构成的最大正方形是多大。(柱子只能竖着放)
解题思路:
将柱子排序,从后往前遍历,模拟正方形变大时所需要的最小柱子是多大就行了。
代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int N=1e3+10;
int T,n,m,k,ans;
int a[N];
int main(){
    cin>>T;
    while(T--){
        cin>>n;
        ans=0;
        for(int i=0;i<n;i++)cin>>a[i];
        sort(a,a+n);
        for(int i=n-1;i>=0;i--){
            if(a[i]>=ans+1)ans++;
            else break;
        }
        cout<<ans<<endl;
    }
    return 0;
}

B1:Character Swap (Easy Version)
题意:
给出两个长度相等的字符串,你可以进行一次操作,该操作可以将两个字符串各一个字符交换,问是否可以进行交换后两个字符串相等。
解题思路:
若能相等,那么肯定仅存在两处字符不相等的地方,所以可以找到两个字符不相等的位置进行交换,最后判断字符串是否相等即可。
代码如下:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e3+10;
int T,n,m,k,ans;
int a[27],b[27];
string s1,s2;
int main(){
    cin>>T;
    while(T--){
        cin>>n>>s1>>s2;
        for(int i=0;i<n;i++){//找到两个字符不相等得位置并退出
            if(s1[i]!=s2[i]){
                for(int j=i+1;j<n;j++){
                    if(s1[j]!=s2[j]){
                        swap(s1[i],s2[j]);
                        break;
                    }
                }
                break;
            }
        }
        if(s1==s2)cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

B2:Character Swap (Hard Version)
题意:
与上一题不同,这道题可以进行2*n次操作,问最后两个字符串能否相等,可以输出操作方案。
解题思路:
考虑贪心,假设我们已经考虑到了i位置,[0,i)区间的都已经相同了。
如果s1[i]!=s2[i]的情况,我们考虑首先交换s1[i]和s2[j],即能否在t里面找到和t[i]相同的;如果没有,我们再从s里面去找即可。假设s1[j]=s2[i],那么我们交换s1[j]和s2[n-1],再交换s1[i]和s2[n-1],只需要两次操作就可以使得s1[i]变成s2[i]了,那么我们这样最多操作2n次,就可以使得s1=s2了。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e3+10;
int T,m,k,n,t;
int ans[N][2];
string s1,s2;
void solve(){
    cin>>n>>s1>>s2;
    t=0;
    for(int i=0;i<n;i++){
        bool is=false;
        if(s1[i]!=s2[i]){//先从s2中找
            for(int j=i+1;j<n;j++){
                if(s2[j]==s2[i]){
                    ans[t++][0]=i+1,ans[t-1][1]=j+1;
                    swap(s2[j],s1[i]);
                    is=true;break;
                }
            }
            if(!is){//如果没找到从s1找
                for(int j=i+1;j<n;j++){
                    if(s1[j]==s2[i]){
                        ans[t++][0]=j+1,ans[t-1][1]=n;
                        ans[t++][0]=i+1,ans[t-1][1]=n;
                        swap(s1[j],s2[n-1]);swap(s1[i],s2[n-1]);
                        is=true;break;
                    }
                }
            }
            if(!is){//如果都没有找到,则不能相等输出no
                cout<<"No"<<endl;return;
            }
        }
    }
    cout<<"Yes"<<endl<<t<<endl;
    for(int i=0;i<t;i++)cout<<ans[i][0]<<" "<<ans[i][1]<<endl;
    return ;
}
int main(){
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

C:Tile Painting
题意:
现在有长度为n个方格需要染色,现在假设i这个格子染色了,那么所有的j满足 |j-i|>1 且 n%|j-i| == 0的格子都需要是同一个颜色,问最多可以染多少种颜色。
解题思路:
首先若该数字位质数,则答案就是n,所有首先将答案赋为n;
然后考虑循环节。
我们枚举n的所有的因子 a[1],a[2],a[3]…a[x]。翻译过来就是我们每a[1]个,都得相同;每a[2]个都得相同;…;每a[x]个都得相同。
那么实际上这个东西的循环节就等于他们的最小公倍数。那么最多个颜色就是n/lcm,实际上就是gcd。因为gcd x lcm = n。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e3+10;
int T,m,k;
int a[27],b[27];
string s1,s2;
ll n,ans;
ll gcd(ll x,ll y){return x%y==0?y:gcd(y,x%y);}
int main(){
    cin>>n;
    ans=n;
    for(ll i=2;i*i<=n;i++){
        if(n%i==0){//有因子就计算gcd
            ans=gcd(ans,i);
            ans=gcd(ans,n/i);
        }
    }
    cout<<ans;
    return 0;
}

D:0-1 MST
题意:
给出一张完全图,最开始每一条边都是权值都为0,再输入m条边,每一条边得权值都变为1,问最后该图得最小生成树权值最小是多少。
解题思路:
考虑边权为0的点,如果两个节点之间的边权为0,那么这两个点可以变成一个点,相当于一个连通块,那么最后这张图可以变成几个点,想要连成最小生成树就需要添加几条边权为1的边就行,所以这道题可以变成这张图一共有多少连通块,那么答案就是连通块的数量减1。所以我们需要维护两个set集合进行优化,一个集合是当前已经聚合成连痛块的点,和一堆还在外面没有讨论过的点。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
int T,m,k,n,ans;
set<int>node[N];//记录每一个节点与之相连的边权为1节点是多少
set<int>f;//记录还未加入连通块的节点
int vis[N];//判断节点是否被访问
void dfs(int x){
    vis[x]=1;
    f.erase(x);//f已经考虑就不再考虑了
    vector<int>now;
    for(int i:f){
        if(!node[x].count(i)){//找到与搜索点相连的边权为0的点加入到now中
            now.push_back(i);
        }
    }
    for(int i:now)f.erase(i);//删除与该点相连的点,相当于将这几个点缩成一个点,就是连通块
    for(int i:now)dfs(i);//搜索其它相连的点
}
int main(){
    cin.sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        node[x].insert(y);
        node[y].insert(x);
    }
    for(int i=1;i<=n;i++)f.insert(i);//先将所有点都加入到非连通块中
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            ans++;
            dfs(i);
        }
    }
    cout<<ans-1;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值