Codeforces Round #656 (Div. 3)(ABCDE题解)

在这里插入图片描述
在这里插入图片描述
题面大意:
给你 x , y , z x,y,z x,y,z,并且满足 x = m a x ( a , b ) , y = m a x ( a , c ) , z = m a x ( b , c ) x=max(a,b),y=max(a,c),z=max(b,c) x=max(a,b),y=max(a,c),z=max(b,c),要你输出 a , b , c a,b,c a,b,c
思路:
通过观察可以发现要满足上面的式子必然存在两个或者以上的最大值。
然后就可以分三种情况讨论 x = y , x = z , y = z x=y,x=z,y=z x=y,x=z,y=z,对于不同的情况令最大值为它们相同的那个数,然后次大值输出本身,最后一个数输出1就行了。
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<set>
using namespace std;

typedef long long int ll;
const int maxn = 2e5 + 10;
bool cmp(int a,int b){
    return a > b;
}
void solved(){
    int p[4];
    cin>>p[1]>>p[2]>>p[3];
    int x = p[1],y = p[2],z = p[3];
    sort(p + 1, p + 4,cmp);
    if(p[1] != p[2]){
        cout<<"NO"<<endl;return;
    }
    cout<<"YES"<<endl;
    if(x == y){
        cout<<p[1]<<" "<<z<<" 1"<<endl;
    }else if(x == z){
        cout<<y<<" "<<p[1]<<" "<<1<<endl;
    }else if(y == z){
        cout<<"1 "<<x<<" "<<p[1]<<endl;
    }
}
int main(){
    int t;cin>>t;
    while(t--)
    solved();
    return 0;
}

在这里插入图片描述
在这里插入图片描述
题面大意:给你一个排列,然后它会插入一个排列,要你输出它插入排列的顺序。
思路:当某个数字出现两次说明是第二个排列,然后输出它就行了。
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<set>
using namespace std;

typedef long long int ll;
const int maxn = 2e5 + 10;
ll a[maxn];
void solved(){
    int n;cin>>n;
    map<int,int>mp;
    for(int i = 1; i <= 2 * n; i++){
        int x;cin>>x;
        mp[x]++;
        if(mp[x] == 2)cout<<x<<" ";
    }
    cout<<endl;
}
int main(){
    int t;cin>>t;
    while(t--)
    solved();
    return 0;
}

在这里插入图片描述
在这里插入图片描述
题面大意:
给你一个序列,要你删掉最短的前缀,使得剩下的序列可以构成非递减的。构成的规则是:把第一个元素或者最后一个元素追加到一个新的序列中,然后从原序列删掉。
思路:
容易发现要使得构成非递减序列,可以是单峰序列,或者是递增的序列,所以我们从最后往前面找一个最长的单峰序列就行了。
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<set>
using namespace std;

typedef long long int ll;
const int maxn = 2e5 + 10;
int a[maxn];
void solved(){
    int n;cin>>n;
    for(int i = 1; i <= n; i++){
        cin>>a[i];
    }
    int r = n;
    while(r - 1 >= 1 && a[r] <= a[r - 1])r--;
    while(r - 1 >= 1 && a[r] >= a[r - 1])r--;
    cout<<r - 1<<endl;
}
int main(){
    int t;cin>>t;
    while(t--)
    solved();
    return 0;
}

在这里插入图片描述
在这里插入图片描述
题面大意:
给你一个小写字符串,你可以修改任意位置的字符为你想要的字符,使得它是一个 a a a好串,要你输出最少修改次数。
a a a好串的定义是:一个字符串前面一半是 a a a,后面一半是 a + 1 a+1 a+1好串,或者后面一半是 a a a好串,前面一半是 a + 1 a+1 a+1好串。 a + 1 a+1 a+1好串是递归定义。
例如这个例子:
在这里插入图片描述
思路:
直接暴力构造所有 a a a好串,然后比较找最小要修改的。
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<set>
using namespace std;

const int maxn = 131072 + 10;
char c[maxn];
int N,ans;
int dfs(int n,int l,int r,char str){
    if(n == 0){
        if(str == c[l])return 0;
        return 1;
    }
    int res = 1e8;
    int cnt1 = 0;
    for(int i = l; i < l + n; i++){
        if(c[i] != str)cnt1++;
    }
    int cnt2 = 0;
    for(int i = l + n; i <= r; i++){
        if(c[i] != str)cnt2++;
    }
    res = min(dfs(n/2,l + n,r,str + 1) + cnt1,dfs(n/2,l,l+n-1,str + 1) + cnt2);
    return res;
}
void solved(){
    cin>>N;
    ans = 1e8;
    scanf("%s",c + 1);
    cout<<dfs(N / 2,1,N,'a')<<endl;
}
int main(){
    int t;scanf("%d",&t);
    while(t--)
    solved();
    return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题目大意:
给你一个图(含有有向边+无向边),无向边需要我们确定方式,使得整个图是一个DAG。
思路:
不管无向边,先队有向图拓扑排序,如果存在环必定不行,如果不存在环,必定可以。
拓扑排序的时候求一个拓扑序,然后根据拓扑序的先后关系输出即可。
代码:

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstring>
using namespace std;

typedef long long int ll;
const int maxn = 2e5 + 10;
int deg[maxn << 1];
int n,m;
int dfn[maxn << 1];
int cnt = 0;
pair<int,int>ve[maxn << 1];
vector<vector<int> >G;
void bfs(){
    queue<int>st;
    for(int i = 1; i <= n; i++){
        if(deg[i] == 0)st.push(i);
    }
    while(!st.empty()){
        int cur = st.front();st.pop();
        dfn[cur] = ++cnt;
        for(int i = 0; i < G[cur].size(); i++){
            int v = G[cur][i];
            if(--deg[v] == 0)st.push(v);
        }
    }
}
void solved(){
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n * 2; i++)dfn[i] = 0,deg[i] = 0;
    cnt = 0;
    G = vector<vector<int> >(n + 1);
    for(int i = 1; i <= m; i++){
        int t,x,y;scanf("%d%d%d",&t,&x,&y);
        ve[i] = make_pair(x,y);
        if(t == 1){
            G[x].push_back(y);
            deg[y]++;
        }
    }
    bfs();
    if(cnt < n){
        puts("NO");
    }else{
        puts("YES");
        for(int i = 1; i <= m; i++){
            int u = ve[i].first;
            int v = ve[i].second;
            if(dfn[u] > dfn[v])printf("%d %d\n",v,u);
            else printf("%d %d\n",u,v);
        }
    }
}
int main(){
    int t;scanf("%d",&t);
    while(t--) solved();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值