Codeforces Round #656 (Div. 3)ABCDE题解(递归二分、拓扑)

A. Three Pairwise Maximums

题目链接

https://codeforces.com/contest/1385/problem/A

思路

将a, b, c非递减排序后得,x=b,y=z=c
若y 不等于 z则无解,否则a=1, b=x, c=y是一组解

代码

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const double pi = acos(-1.0);
#define INF 0x7f7f7f
// #define TDS_ACM_LOCAL
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    int t;
    cin>>t;
    while(t--){
        int x, y, z;
        cin>>x>>y>>z;
        if(x>y) swap(x,y);
        if(x>z) swap(x,z);
        if(y>z) swap(y,z);
        if(y==z)
        {
            cout<<"YES"<<endl;
            cout<<"1 "<<x<<" "<<y<<endl;
        }   
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

B. Restore the Permutation by Merger

题目链接

https://codeforces.com/contest/1385/problem/B

思路

第二次遇到相同的就输出

代码

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const double pi = acos(-1.0);
#define INF 0x7f7f7f
// #define TDS_ACM_LOCAL
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    int t;
    cin>>t;
    while(t--){
        int n, a, p[55]={0};
        cin>>n;
        for(int i=0; i<2*n; i++){
            cin>>a;
            p[a]++;
            if(p[a]==2)
                cout<<a<<" ";
        }
        cout<<endl;
    }
    return 0;
}

C. Make It Good(逆向求峰顶峰底)

题目链接

https://codeforces.com/contest/1385/problem/C

思路

满足题目要求的很明显
1、全程不变
2、全程非递减或者非递增
3、具有一个极大值的峰顶
解:从右到左搜索峰顶(>=),再从峰顶往左搜峰底(<=)

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
using namespace std;
const double pi = acos(-1.0);
#define INF 0x7f7f7f
// #define TDS_ACM_LOCAL
#define mem(a,b) memset(a , b , sizeof(a))
#define FOR(i, x, n) for(int i = x;i <= n; i++)
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    int t;
    cin>>t;
    while(t--){
        int n, a[200009]={0};
        cin>>n;
        for(int i=0; i<n; i++)
            cin>>a[i];
        int k=n-1;
        while(a[k-1]>=a[k]&&k>=1)
            k--;
        while(a[k-1]<=a[k]&&k>=1)
            k--;
        cout<<k<<endl;
    }
    return 0;
}

D. a-Good String(二分、递归)

题目链接

https://codeforces.com/contest/1385/problem/D

思路

因为n=2^k,所以n为2的倍数,可以一直二分到只有一个字符
使用递归二分的方法,每次分别计算当前子串的左边和右边变成c需要的操作次数,将各种情况下的次数求和取最小即可

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
using namespace std;
const double pi = acos(-1.0);
#define INF 0x7f7f7f
// #define TDS_ACM_LOCAL
#define mem(a,b) memset(a , b , sizeof(a))
#define FOR(i, x, n) for(int i = x;i <= n; i++)

inline void read(int &x) {
	char ch = getchar(); int f = 1; x = 0;
	while (!isdigit(ch) && ch^'-') ch = getchar();
	if (ch == '-') f = -1, ch = getchar();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
	x *= f;
}

char s[131080];
int t, n, ans;

int solve(int l, int r, char c){                                         //字符c按照abcd...排序
    if(l==r)    return s[l]==c? 0:1;                                     //最后一位数时不需要变返回0,否则1
    int mid=(l+r)>>1, left=0, right=0;                                   //求得当前子串的左右分别需要改变的字符的数量
    FOR(i, l, mid)  left+=(s[i]==c? 0:1);                                //判断当前字符是否需要进行改变
    FOR(i, mid+1, r)    right+=(s[i]==c? 0:1);
    return min(left+solve(mid+1, r, c+1), right+solve(l, mid, c+1));     //采用递归的方法求改变的最小值
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    read(t);
    while (t--)
    {
       read(n);
       scanf("%s", s+1);
       ans=solve(1, n, 'a');
       cout<<ans<<endl;
    }
    return 0;
}

E. Directing Edges

题目链接>

https://codeforces.com/contest/1385/problem/E

思路

因为题目要求无环,所以使用toposort(拓扑排序),以已知的有向边计算入度进行拓扑排序
检测是否所有的点都在拓扑序列中,有剩余的点说明有环
因为先去除的点排在前面,后去除的点排在后面,所以从前面向后面添加边是不会对拓扑序列造成影响
所以将无向边变成有向边的时候按照前面的点到后面的点连向就行

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define pb push_back
#define mp make_pair
#define X first
#define Y second
const int N=200009;
// #define TDS_ACM_LOCAL

int tx, n, m, a[N], in_degree[N];
int t, x, y;
vector<pair<int,int>> ma[N];
vector<int>topo;

inline void read(int &x) {
	char ch = getchar(); int f = 1; x = 0;
	while (!isdigit(ch) && ch^'-') ch = getchar();
	if (ch == '-') f = -1, ch = getchar();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
	x *= f;
}

void toposort(){
    topo.clear();                                //拓扑序列初始化
    queue<int>q;                                 //存点的队列
    for(int i=1; i<=n; i++)                      //将入度为0的点放入队列中
        if(!in_degree[i])
            q.push(i);
    while(q.size()){
        x=q.front();
        q.pop();
        topo.pb(x);                             //将点放入拓扑序列中
        for(int i=0; i<ma[x].size(); i++){      //将该点能到达的有向边全部删除(即可到达点的入度减1
            y=ma[x][i].X, t=ma[x][i].Y;
            if(t){
                if(!--in_degree[y])
                    q.push(y);
            }
        }
    }
}

void solve(){
    read(n), read(m);
    for(int i=1; i<=n; i++) {        //初始化每个点的入度和图
        in_degree[i]=0;
        ma[i].clear();
    }
    while(m--){
        read(t), read(x), read(y);
        if(t){                       //为有向边,记录x->y,并且标记为有向边,同时入度加1
            ma[x].pb(mp(y,t));
            in_degree[y]++;
        } 
        else{                        //为无向边,记录x->y,y->x,并且标记为无向边
            ma[x].pb(mp(y,t));
            ma[y].pb(mp(x,t));
        }
    }
    toposort();
    if(topo.size()!=n){              //拓扑序列没有包含所有点,说明有环
        cout<<"NO"<<endl;
        return ;
    }
    else{
        cout<<"YES"<<endl;
        for(int i=0; i<n; i++)       //记录拓扑序列的点的先后顺序
            a[topo[i]]=i;
        for(int i=1; i<=n; i++){
            for(int j=0; j<ma[i].size(); j++){        //输出所有的边
                y=ma[i][j].X, t=ma[i][j].Y;
                if(t)                                 //有向边直接输出
                    cout<<i<<" "<<y<<endl;
                else{                                 //无向边按照在拓扑序列出现的先后顺序输入
                    if(a[i]<a[y])
                        cout<<i<<" "<<y<<endl;
                }
            }
        }
    }
    
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    read(tx);
    while (tx--) solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xmyrzb/article/details/107443484