Codeforces Round #656 (Div. 3)

A.Three Pairwise Maximums

首先最大的在原序列中肯定出现至少两次否则不能构造,即min max max,对于答案min min max肯定满足题意

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int main()
{
    IO;
    int T;
    cin>>T;
    while(T--)
    {
        int x,y,z;
        cin>>x>>y>>z;
        if(x>y) swap(x,y);
        if(y>z) swap(y,z);
        if(x>y) swap(x,y);
        if(z!=y) cout<<"NO"<<endl;
        else 
        {
            cout<<"YES"<<endl;
            cout<<x<<" "<<x<<" "<<y<<endl;
        }
    }
    return 0;
}
B. Restore the Permutation by Merger

第二题直接开个map记录一下就行了。最气的是wa了一次(数组开小了我🤮了)

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=60;//最开始N=50 wa了一次,这种低级错误我🤮了
int mp[N],n;
int main()
{
    IO;
    int T;
    cin>>T;
    while(T--)
    {
        memset(mp,0,sizeof mp);
        cin>>n;
        for(int i=1;i<=2*n;i++)
        {
            int a;
            cin>>a;
            if(mp[a]) continue;
            mp[a]=1;
            cout<<a<<" ";
        }
        cout<<endl;
    }
    return 0;
}
C. Make It Good

这题就是从后往前找^就行了。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=200010;
int a[N],n;
int main()
{
    IO;
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        int i=n;
        for(;i;i--)
            if(a[i]>a[i-1]) break;
        int j=i;
        for(;j;j--) 
            if(a[j]<a[j-1]) break;
        if(j==0) cout<<j<<endl;
        else cout<<j-1<<endl;
    }
    return 0;
}
D. a-Good String

看数据范围,对于 2 16 = 65536 2^{16}=65536 216=65536所以直接暴力就行了,分而治之。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
const int N=200010;
int n; 
string s;
int res=0x3f3f3f3f;
void dfs(int l,int r,int x,int ans)
{
    if(ans>=res) return;
    if(r==l)
    {
        if(s[l]!=char('a'+x)) ans++;
        res=min(res,ans);
    }
    int mid=l+r>>1;
    int cnt1=0,cnt2=0;
    for(int i=l;i<=mid;i++)
        if(s[i]!=char('a'+x)) cnt1++;
    dfs(mid+1,r,x+1,ans+cnt1);
    for(int i=mid+1;i<=r;i++)
        if(s[i]!=char('a'+x)) cnt2++;
    dfs(l,mid,x+1,ans+cnt2);
}
int main()
{
    IO;
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        cin>>s;
        res=0x3f3f3f3f;
        dfs(0,n-1,0,0);
        cout<<res<<endl;
    }
    return 0;
}

做了上面四个题,比之前多做一题。-。-还是太菜

E.Directing Edges

昨天晚上打完比赛后,躺在床上就想这个题,突然灵光一现,发现只需要搞个拓扑排序就行了。今天早上起晚了,醒了就赶快写了一下发现漂亮的AC了。
先不考虑无向边,对有向边进行拓扑排序,如果有向边不是拓扑序那么答案肯定是YES否则答案肯定是NO,对于不考虑无向边的拓扑序肯定是一些拓扑序,只要对无向边从拓扑序前面向拓扑序后面连边,肯定不会出现环。对于两个独立的拓扑序,也可以按照上述方式连边。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef pair<int,int> pii;
const int N=200010,M=400010;
int n,m;
int h1[N],h2[N],e[M],ne[M],idx;
bool st[N];
int cnt;
vector<pii> res;
void add(int h[],int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
int q[N],d[N];
bool top_sort()
{
    int tt=-1,hh=0;
    for(int i=1;i<=n;i++)
        if(!d[i]) q[++tt]=i;
    while(tt>=hh)
    {
        int t=q[hh++];
        st[t]=1;
        for(int i=h2[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(st[j]) continue;
            res.push_back({t,j});
        }
        for(int i=h1[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(!(--d[j])) q[++tt]=j;
        }
    }
    return tt==n-1;
}
int main()
{
    IO;
    int T;
    cin>>T;
    while(T--)
    {
       memset(h1,-1,sizeof h1);
       memset(h2,-1,sizeof h2);
       memset(st,0,sizeof st);
       memset(d,0,sizeof d);
       idx=0,cnt=0;
       res.clear();
       cin>>n>>m;
       for(int i=0;i<m;i++) 
       {
           int t,x,y;
           cin>>t>>x>>y;
           if(t) 
           {
               res.push_back({x,y});
               add(h1,x,y);
               d[y]++;
           }
           else 
           {
               add(h2,x,y);
               add(h2,y,x);
           }
       }
       if(!top_sort()) cout<<"NO"<<endl;
       else
       {
            cout<<"YES"<<endl;
            for(auto t:res) cout<<t.first<<" "<<t.second<<endl;
       }
    }
    return 0;
}

之前每次都是补五题,不过这次的五题可以算是自己独立做出来的(虽然E)所以有时间可以把F、G看看题解更新一下。要加油哦~

F - Removing Leaves

①维护leaf[i]表示与第i个节点相邻叶子(度数为1)的数量
②维护s[i]表示与第i个节点相邻并且不是叶子节点的编号(用STL中的set记录
③优先队列维护leaf[],按照每个节点的叶子数量排序(叶子节点多的优先级高)
每次取出对头,只要能一次删除k个就删除并统计答案同时更新每个点的度数和相邻叶子数量,倘若一个点tleaf[t]==0&&d[t]==1说明该点在删除自己之前的叶子节点后自己变成了叶子节点,那么要更新s[t]中节点的叶子数量(这时候s[t]中有且只有一个节点v),t已经成了叶节点所以需要s[v].erase(t),然后加入队列循环此过程。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<queue>
using namespace std;
const int N=200010,M=400010;
int h[N],e[M],ne[M],idx,d[N];
int n,m;
int leaf[N];//每个点相邻叶子节点的数量
set<int> s[N];//每个点相邻不是叶子节点
struct node
{
    int id,cnt;
    bool operator < (const node &o) const
    {
        return cnt<o.cnt;
    }
};
priority_queue<node> heap;
void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
    d[b]++;
}
void init()
{
    for(int i=0;i<=n;i++)
    {
        s[i].clear();
        h[i]=-1;
        d[i]=0;
        leaf[i]=0;
    }
    while(heap.size()) heap.pop();
    idx=0;
}
void dfs(int u,int fa)
{
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(j==fa) continue; 
        //由于边是双向的,需要双向加!!!
        //d[]>1说明不是叶子节点 d[]==1说明是叶子节点
        if(d[j]>1) s[u].insert(j); 
        if(d[u]>1) s[j].insert(u);
        if(d[j]==1) leaf[u]++;
        if(d[u]==1) leaf[j]++;
        dfs(j,u);
    }
}
int main()
{
    IO;
    memset(h,-1,sizeof h);
    int T;
    cin>>T;
    while(T--)
    {
        init();
        cin>>n>>m;
        for(int i=1;i<n;i++)
        {
            int a,b;
            cin>>a>>b;
            add(a,b),add(b,a);
        }
        if(m==1)
        {
            cout<<n-1<<endl;
            continue;
        }
        dfs(1,-1);
        for(int i=1;i<=n;i++)
            if(leaf[i]>=m) heap.push({i,leaf[i]});
        int res=0;
        while(heap.size())
        {
            if(heap.top().cnt!=leaf[heap.top().id]) 
            {
                heap.pop();
                continue;
            }
            int t=heap.top().id;heap.pop();
            if(leaf[t]<m) break;
            else 
            {
                res+=leaf[t]/m;
                d[t]-=leaf[t]/m*m;
                leaf[t]%=m;
                if(leaf[t]==0&&d[t]==1)
                {
                    int v=*s[t].begin();
                    leaf[v]++;
                    s[v].erase(t);
                    if(leaf[v]>=m) heap.push({v,leaf[v]});
                }
            }
        }
        cout<<res<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值