Language: HTML document.onkeydown=function (e){ var currKey=0,evt=e||window.event; currKey=evt.keyCode||evt.which||evt.charCode; if (currKey == 123) { window.event.cancelBubble = true; window.event.returnValue = false; } }

Codeforces Round #656 (Div.3) 解题报告

Codeforces Round #656 (Div. 3)

原文链接 https://www.cnblogs.com/-Dominate-/p/13550490.html

A. Three Pairwise Maximums

思路

分类讨论,x、y、z三个数有两个数相等且另一个数小于等于这两个数就能找到合法的a、b、c,具体直接看代码吧。(水题练下python)

T=int(input())
for i in range(T):
    x,y,z=map(int,input().split())
    if x==y:
        if z>x:
            print("NO")
            continue
        else:
            print("YES")
            print(x,z,1)
    elif x==z:
        if y>x:
            print("NO")
            continue
        else:
            print("YES")
            print(y,x,1)
    elif y==z:
        if x>y:
            print("NO")
            continue
        else:
            print("YES")
            print(1,x,z)
    else:print("NO")

B. Restore the Permutation by Merger

思路

简单贪心,每次碰到不同的数直接输出或者记录下来最后输出都ok。

T=int(input())
for tt in range(T):
    hh=[]
    vis=[0]*200
    ans=[]
    n=int(input())
    hh=list(map(int,input().split()))
    for i in hh:
        if vis[i]==0:
            ans.append(i)
            vis[i]=1
    for i in ans:
        print(i,end=' ')

C. Make It Good

思路

因为只能删前缀,所以很容易想到从后往前找一个倒序先增后减序列,碰到“谷”直接记录序号退出循环输出就好了。

#include<bits/stdc++.h>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
int a[200050];
// inline int read()
// {
//     int x=0,f=1;char ch=getchar();
//     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
//     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
//     return x*f;
// }
int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	IO;
    int t;cin>>t;
    while(t--)
    {
        int n;cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        int f=0,ans=0;
        for(int i=n-1;i>=1;i--)
        {
            if(!f)
            {
                if(a[i]<a[i+1])f=1;
            }
            else 
            {
                if(a[i]>a[i+1]){ans=i;break;}
            }
        }
        cout<<ans<<"\n";
    }
    return 0;
}

D. a-Good String

思路

读完题发现很明显的分治,n是2的17次方,写个递归暴力就能过。

#include<bits/stdc++.h>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
char s[132000];
// inline int read()
// {
//     int x=0,f=1;char ch=getchar();
//     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
//     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
//     return x*f;
// }
int solve(int l,int r,char ch)
{
    if(l==r)return s[l]!=ch;
    int mid=l+r>>1;
    int cntl=0,cntr=0;
    for(int i=l;i<=mid;i++)if(s[i]!=ch)cntl++;
    for(int i=mid+1;i<=r;i++)if(s[i]!=ch)cntr++;
    int ans1=solve(mid+1,r,ch+1),ans2=solve(l,mid,ch+1);
    return min(ans1+cntl,ans2+cntr);
}
int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	IO;
    int t;cin>>t;
    while(t--)
    {
        int n;cin>>n;
        cin>>s+1;
        cout<<solve(1,n,'a')<<'\n';
    }
    return 0;
}

E. Directing Edges

思路

感觉是道好题,有向无向边需要分开处理,拓扑排序来避免环的出现也很妙。首先对所有的有向边建图判环,有环直接输出NO,无环则剩下的边可以按照拓扑序从小到大连边,拓扑序就按编号从小到大连边。根据拓扑排序的原理,一个点在访问过后不会再被访问,可以完美避免环的出现。
此处有参考suxxsfe的题解,传送门

#include<bits/stdc++.h>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int maxn=2e5+50;
int Head[maxn],V[maxn*2],Nxt[maxn*2],du[maxn],vis[maxn],crcl[maxn],step[maxn];
int tot,cnt,cntt,cnttt;
int n,m;
pair<int,int>e[maxn],ee[maxn];
void Add(int u,int v){V[++tot]=v;Nxt[tot]=Head[u];Head[u]=tot;}
int dfs(int u)
{
    vis[u]=crcl[u]=1;
    for(int i=Head[u];i;i=Nxt[i])
    {
        int v=V[i];
        if(crcl[v])return 1;
        if(!vis[v])
        {
            int tmp=dfs(v);
            if(tmp)return 1;
        }
    }
    crcl[u]=0;
    return 0;
}
void topsort(){
    queue<int>p,q;
    int i,u,v;
    for(i=1;i<=n;i++)if(!du[i])q.push(i);
    while(!q.empty()){
        cnt++;
        while(!q.empty())
        {
            u=q.front();q.pop();
            step[u]=cnt;
            for(i=Head[u];i;i=Nxt[i])
            {
                v=V[i];
                du[v]--;
                if(!du[v])p.push(v);
            }    
        }
    swap(p,q);
    }
}
int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	IO;
    int t;cin>>t;
    while(t--)
    {
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            int type,u,v;
            cin>>type>>u>>v;
            if(type)
            {
                Add(u,v);du[v]++;
                ee[++cnttt].first=u;ee[cnttt].second=v;
            }
            else e[++cntt].first=u,e[cntt].second=v;
        }
        int f=0;
        for(int i=1;i<=n;i++)
            if(!vis[i])
            {
                int tmp=dfs(i);
                if(tmp){f=1;break;}
            }
        if(f){cout<<"NO\n";}
        else
        {
            topsort();
            cout<<"YES\n";
            for(int i=1;i<=cnttt;i++)
                cout<<ee[i].first<<" "<<ee[i].second<<"\n";
            for(int i=1;i<=cntt;i++)
                if(step[e[i].first]<step[e[i].second]||(step[e[i].first]==step[e[i].second]&&e[i].first<e[i].second))cout<<e[i].first<<" "<<e[i].second<<"\n";
                else cout<<e[i].second<<" "<<e[i].first<<"\n";
        }
        for(int i=1;i<=n;i++)Head[i]=vis[i]=crcl[i]=du[i]=0;
	    tot=cnt=cntt=cnttt=0;
    }
    return 0;
}

F. Removing Leaves

思路

读完题思路很明确,一直贪心删叶节点就好了,但是自己实现的时候发现光用vector不太行(太菜了QAQ),后来参考了大神代码发现加上队列或者集合维护就很好写。
此处有参考 nofuck~ 大神的代码。传送门

#include<bits/stdc++.h>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int maxn=2e5+50;
vector<int> g[maxn];
int du[maxn],vis[maxn],sz[maxn];
int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	IO;
	int t;cin>>t;
	while(t--)
    {
        int n,k,ans=0;cin>>n>>k;
        for(int i=1;i<n;i++)
        {
            int u,v;cin>>u>>v;
            g[u].push_back(v);g[v].push_back(u);
            du[u]++;du[v]++;
        }
        queue<int> q;
        for(int i=1;i<=n;i++)
            if(du[i]==1)q.push(i);
        while(!q.empty())
        {
            int u=q.front();q.pop();vis[u]=1;
            for(auto v:g[u])
            {
                if(vis[v])continue;
                du[v]--;sz[v]++;
                if(sz[v]%k==0)ans++;
                if(du[v]==1&&sz[v]%k==0)q.push(v);
            }
        }
        cout<<ans<<"\n";
        for(int i=1;i<=n;i++)
            du[i]=vis[i]=sz[i]=0,g[i].clear();
    }
    return 0;
}

G. Columns Swaps

思路

一开始有想到类似的题,比如洛谷的关押罪犯和食物链,感觉用并查集+分身法可以解决,然后不太想写逛题解的时候发现有人提到二分图染色可以做,于是果断开始写二分图染色,然后日常写挂后%大神代码。。
核心想法就是如果一行有两个a,那么必有一个换另一个不换;如果一行只有一个a,那么这列不换另一个a的列也不换,这列换另一个a的列也要换。
此处有参考 ..vince 大神的代码。传送门

#include<bits/stdc++.h>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int maxn=2e5+50;
int A[maxn],B[maxn],vis[maxn],col[maxn];
vector<int>pos[maxn];
vector<int>V[maxn];
vector<int>cols[2];
vector<int>ans;
int n,f;
void init()
{
    f=0;
    ans.clear();
    for(int i=1;i<=n;i++)
    {
        vis[i]=col[i]=0;
        pos[i].clear();
        V[i].clear();
    }
}
bool cal(int u,int v){return A[u]==A[v]||B[u]==B[v];}
void dfs(int u,int c)
{
    col[u]=c;
    cols[c].push_back(u);
    vis[u]=1;
    for(int v: V[u])
    {
        if(vis[v])
        {
            if(col[u]^cal(u,v)!=col[v])f=1;
            continue;
        }
        dfs(v,c^cal(u,v));
    }
}
int main()
{
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	IO;
	int t;cin>>t;
    while(t--)
    {
        init();
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            int x;cin>>x;A[i]=x;
            pos[x].push_back(i);
        }
        for(int i=1;i<=n;i++)
        {
            int x;cin>>x;B[i]=x;
            pos[x].push_back(i);
        }
        int ff=0;
        for(int i=1;i<=n;i++)
        {
            if(pos[i].size()!=2)
            {
                ff=1;
                break;
            }
            if(pos[i][0]==pos[i][1])continue;
            V[pos[i][0]].push_back(pos[i][1]);
            V[pos[i][1]].push_back(pos[i][0]);
        }
        if(ff){cout<<"-1\n";continue;}
        for(int i=1;i<=n;i++)
            if(!vis[i])
            {
                cols[0].clear();cols[1].clear();
                dfs(i,0);
                if(cols[0].size()<cols[1].size())
					for(auto x:cols[0])
						ans.push_back(x);
				else 
					for(auto x:cols[1])
						ans.push_back(x);
            }
        if(f){cout<<"-1\n";continue;}
        int len=ans.size();
        cout<<len<<"\n";
        for(int i=0;i<len;i++)
        {
            cout<<ans[i];
            if(i==len-1)cout<<'\n';
            else cout<<" ";
        }
        if(len==0)cout<<'\n';
    }
    return 0;
}
posted @ 2020-08-23 20:16  DDDOMINATE  阅读(231)  评论(0)    收藏  举报