这场本来赛中卡了D,按理说是要掉分的

A - Three Pairwise Maximums

题意:x=max(a,b),y=max(a,c),z=max(b,c),现在给定x,y,z,求a,b,c。
思路:我们假设a>b>c,那么显然x==y>z,所以可以看出不管a,b,c大小关系如何,x,y,z中必有两个一样,并且大于等于剩下的那个数字,所以只需要让公共的那个值设为大的值,另外两个设为小的值即可。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdlib>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<set>
#define fi first
#define se second
#define pb push_back
#define me(a,b) memset(a,b,sizeof(a))
#define INIT() std::ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
const int MAX_N=15+5;
const int MAX_M=30+5;
const int INF=0x7fffffff;
const int inf=1000000000;
const double EPS=1e-6;
const ull base=123;
const ll mod=998244353;
const double pi=4*atan(1.0);
int main()
{
   
    int t;
    cin>>t;
    while(t--)
    {
   
        int a,b,c;
        cin>>a>>b>>c;
        if(a!=b&&b!=c&&a!=c)
            cout<<"NO"<<endl;
        else
        {
   
            int x,y;
            if(a==b)
            {
   
                x=a;
                y=c;
            }
            if(a==c)
            {
   
                x=a;
                y=b;
            }
            if(b==c)
            {
   
                x=b;
                y=a;
            }
            if(x<y)
            {
   
                cout<<"NO"<<endl;
            }
            else
            {
   
                cout<<"YES"<<endl;
                if(a==x&&b==x)
                {
   
                    cout<<x<<' '<<y<<' '<<y<<endl;
                }
                else if(a==x&&c==x)
                {
   
                    cout<<y<<' '<<x<<' '<<y<<endl;
                }
                else if(b==x&&c==x)
                {
   
                    cout<<y<<' '<<y<<' '<<x<<endl;
                }
            }
 
        }
    }
}

B - Restore the Permutation by Merger

题意:两个同样的n序列,相互穿插在一起,给定穿插后的串,求原串。
思路:因为顺序不变,序列中字母也不会重复,所以直接取第一次出现的字母放在序列末尾即可。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdlib>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<set>
#define fi first
#define se second
#define pb push_back
#define me(a,b) memset(a,b,sizeof(a))
#define INIT() std::ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
const int MAX_N=100+5;
const int MAX_M=30+5;
const int INF=0x7fffffff;
const int inf=1000000000;
const double EPS=1e-6;
const ull base=123;
const ll mod=998244353;
const double pi=4*atan(1.0);
int main()
{
   
    int t;
    cin>>t;
    while(t--)
    {
   
        vector<int>ans;
        map<int,int>vis;
        int a;
        int n;
        scanf("%d",&n);
        int i;
        for(i=1;i<=2*n;i++)
        {
   
            scanf("%d",&a);
            if(!vis[a])
            {
   
                ans.pb(a);
                vis[a]=1;
            }
        }
        for(i=0;i<ans.size();i++)
        {
   
            printf("%d%c",ans[i],i==ans.size()-1?'\n':' ');
        }
    }
}

C - Make It Good

题意:给定一个序列,通过删除前缀,使其每次从开头或结尾拿出一个字符放在新的串的结尾,最后使该串不递减。求删除最短前缀的长度。
思路:首先这个删除后序列要想满足这个不递减的条件,必然要以中间某个字符为界限,从第一个到他,和最后一个到他都是不递减的,然后由于只删前缀,所以我们可以从后往前遍历,找到第一个不满足不递减条件的字符,那么这个位置就可以看做那个届,然后从头开始遍历到这个届,如果遇到递减的字符,那么这个字符之前的就都要删掉。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdlib>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<set>
#define fi first
#define se second
#define pb push_back
#define me(a,b) memset(a,b,sizeof(a))
#define INIT() std::ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
const int MAX_N=200000+5;
const int MAX_M=30+5;
const int INF=0x7fffffff;
const int inf=1000000000;
const double EPS=1e-6;
const ull base=123;
const ll mod=998244353;
const double pi=4*atan(1.0);
int a[MAX_N];
int main()
{
   
    int t;
    cin>>t;
    while(t--)
    {
   
        int n;
        scanf("%d",&n);
        int i;
        for(i=1; i<=n; i++)
            scanf("%d",&a[i]);
        int pos=0;
        for(i=n-1; i>=1; i--)
        {
   
            if(a[i]<a[i+1])
            {
   
                pos=i;
                break;
            }
        }
        if(pos==0)
        {
   
            cout<<0<<endl;
            continue;
        }
        //cout<<a[pos]<<endl;
        int ans=0;
        for(i=2; i<=pos; i++)
        {
   
            if(a[i]<a[i-1])
            {
   
                ans=i-1;
            }
        }
        cout<<ans<<endl;
    }
}

D - a-Good String

题意:不太好描述,诸如aaaabbcd,aaaabbdc,bbdcaaaa这样的串是好串,现在给定一些串,问最少改多少字符可以形成好串。
思路:dfs暴力就完了,顺便吐槽下,用暴力和前缀和记录的时间cf测出来居然是一样的,都只有46ms,太神奇了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdlib>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<set>
#define fi first
#define se second
#define pb push_back
#define me(a,b) memset(a,b,sizeof(a))
#define INIT() std::ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
const int MAX_N=200000+5;
const int MAX_M=30+5;
const int INF=0x7fffffff;
const int inf=1000000000;
const double EPS=1e-6;
const ull base=123;
const ll mod=998244353;
const double pi=4*atan(1.0);
char s[MAX_N];
int ans=INF;
void dfs(int l,int r,char c,int sum)
{
   
    //cout<<l<<' '<<r<<endl;
    if(l==r)
    {
   
        if(s[l]!=c)
            sum++;
        ans=min(ans,sum);
        return;
    }
    int tmp=0;
    int i;
    int mid=(l+r)/2;
    for(i=l;i<=mid;i++)
    {
   
        if(s[i]!=c)
            tmp++;
    }
    //cout<<tmp<<endl;

    dfs(mid+1,r,c+1,sum+tmp);
    tmp=0;
    for(i=mid+1;i<=r;i++)
    {
   
        if(s[i]!=c)
            tmp++;
    }
    //cout<<tmp<<endl;
    dfs(l,mid,c+1,sum+tmp);
}
int main()
{
   
    int t;
    cin>>t;
    while(t--)
    {
   
        ans=INF;
        int n;
        scanf("%d",&n);
        scanf("%s",s+1);
        if(n==1)
        {
   
            if(s[1]=='a')
                cout<<0<<endl;
            else
                cout<<1<<endl;
            continue;
        }
        dfs(1,n,'a',0);
        cout<<ans<<endl;
    }
}

E - Directing Edges

题意:给定n个点和m条边组成的图,这m条边中有些是有向的,有些是无向的,现在要求你给这些无向边加上方向,使其不存在环。
思路:看到成环要想到拓补排序(虽然本菜鸡根本没想到),先把有向边进行拓补排序,顺便判断下是不是已经成环了,然后无向边的两点根据拓补链中的先后,前面的指向后面的。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstdlib>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<set>
#define fi first
#define se second
#define pb push_back
#define me(a,b) memset(a,b,sizeof(a))
#define INIT() std::ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
const int MAX_N=200000+5;
const int MAX_M=30+5;
const int INF=0x7fffffff;
const int inf=1000000000;
const double EPS=1e-6;
const ull base=123;
const ll mod=998244353;
const double pi=4*atan(1.0);
vector<int>edge[MAX_N],ans;;
vector<P>e;
int in[MAX_N];
int n,m;
int vis[MAX_N];
int tuob()//拓补排序
{
   
    //cout<<in[3]<<endl;
    queue<int>q;
    int i;
    for(i=1; i<=n; i++)
    {
   
        if(in[i]==0)
            q.push(i);
    }
    while(!q.empty())
    {
   
        int x=q.front();
        //cout<<x<<endl;
        ans.pb(x);
        vis[x]=ans.size();
        q.pop();
        for(auto i:edge[x])
        {
   
            in[i]--;
            if(in[i]==0)
                q.push(i);
        }
    }
    //cout<<in[3]<<endl;
    if(ans.size()==n)
        return 1;
    else
        return 0;
}
int main()
{
   
    int t;
    cin>>t;
    while(t--)
    {
   
        me(in,0);
        me(vis,0);
        ans.clear();
        e.clear();
        int i;
        scanf("%d%d",&n,&m);
        for(i=0;i<=n;i++)
            edge[i].clear();
        for(i=1; i<=m; i++)
        {
   
            int op,l,r;
            scanf("%d%d%d",&op,&l,&r);
            if(op)
            {
   
                edge[l].pb(r);
                in[r]++;
            }
 
            else
            {
   
                e.pb(P(l,r));
            }//cout<<in[3]<<endl;
        }
        //sort(in+1,in+1+n);
        if(!tuob())
            cout<<"NO"<<endl;
        else
        {
   
            for(auto i:e)
            {
   
                if(vis[i.fi]<vis[i.se])
                {
   
                    edge[i.fi].pb(i.se);
                }
                else
                    edge[i.se].pb(i.fi);
            }
            cout<<"YES"<<endl;
            for(i=1; i<=n; i++)
            {
   
                for(auto j:edge[i])
                {
   
                    cout<<i<<' '<<j<<endl;
                }
            }
        }
    }
}