为了能到远方,脚下的每一步都不能少.|

园龄:粉丝:关注:

Acwing 第 163 场周赛

A

将数据存入数组,根据下标取最小值

B

根据题意,相邻的两个都是朋友,给出朋友关系,构造满足所有关系的排列

假如此时 2 3 1 4 5 满足朋友关系,那么5之后的第一个数字一定是4的朋友,以此递推,就可以得到排列

所以现在的问题在于,如何得到这个最初始的排列?

由于数据较小,我们以1为其他4个数字的朋友,全排列所有的可能,一个一个去检验即可


#include<bits/stdc++.h>

using namespace std;

const int maxn=1e5+10;
int n;
vector<int >q[maxn];
int nt[5],ans[maxn];
bool book[5],used[maxn];

int get(int x,int a,int b,int c){
    for(int v:q[x]){
        if(v!=a && v!=b && v!=c) return v;
    }
    return -1;
}
bool check(){
    ans[2]=1;
    int d[5]={0,1,3,4};
    for(int i=0;i<4;++i) 
        ans[d[i]]=q[1][nt[i]];//排列输入答案
    for(int i=5;i<n+5;++i){
        ans[i]=get(ans[i-2],ans[i-4],ans[i-3],ans[i-1]);//递推后面
        if(ans[i]==-1) return 0;//出现不可能的构造
    }
    for(int i=0;i<5;++i)
        if(ans[i]!=ans[n+i]) return false;//5个应该与前5个重叠
        
    memset(used,0,sizeof used);
    for(int i=0;i<n;++i){//判重,出现重复的即有错
        int t=ans[i];
        if(used[t]) return 0;
        used[t]=1;
    }
    for(int i=0;i<n;++i) printf("%d ",ans[i]);
    return 1;
}
bool dfs(int u){//全排列
    if(u==4) return check();
    for(int i=0;i<4;++i)
    if(!book[i]){
        nt[u]=i;
        book[i]=1;
        if(dfs(u+1)) return true;
        book[i]=0;
    }
    return 0;
}
int main(){
    scanf("%d",&n);
    for(int i=0;i<n*2;++i){
        int u,v;
        scanf("%d %d",&u,&v);
        q[u].push_back(v);
        q[v].push_back(u);
    }
    if(!dfs(0)) puts("-1");
    return 0;
}

C

经典模型

并查集染色

对于一个区间[l,r]的奶农都被其中的x打败,所以用ans记录他们被谁打败

而被打败的奶牛,用并查集f[]指向后一头牛,由于路径压缩,那么区间内的每头牛都会指向r+1,这样下次涉及该区间操作时,就会跳过该区间

该题中第x头牛会被保留,所以删除的区间是[l,x-1],[x+1,r]

#include<bits/stdc++.h> 

using namespace std;

const int maxn= 300010;

int n,m;
int f[maxn], ans[maxn];

int find(int x)
{
    if(f[x] != x)  return f[x] = find(f[x]);
    return f[x];
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i=1; i<=n+1; i++) f[i]=i;
    while (m--)
    {
        int l, r, x;
        scanf("%d%d%d", &l, &r, &x);
        for(int i=find(l);i<x;i=find(i)){
            if (i<x){
                f[i]=i+1;
                ans[i]=x;
            }
        }
        for(int i=find(x+1);i<=r;i=find(i)){
            if (i<=r){
                f[i]=i+1;
                ans[i]=x;
            }
        }
    }
    for (int i=1;i<=n;i++) printf("%d ", ans[i]);
    return 0;
}

类似题疯狂的馒头

  • 温馨提示 cin,cout超时
#include<bits/stdc++.h>

using namespace std;

int n,m,p,q;

int l,r;
const int maxn=2e6+10;
int f[maxn];
int ans[maxn];
int cnt=0;
int find(int x){
    if(x!=f[x]) return f[x]=find(f[x]);
    return x;
    
}
int main(){
    scanf("%d %d %d %d",&n,&m,&p,&q);
    for(int i=1;i<=n+1;++i) f[i]=i;
    while(m){
        int x = (m * p + q) % n + 1;
        int y = (m * q + p) % n + 1;
        l=min(x,y);
        r=max(x,y);
        for(int i=find(l);i<=r;i=find(i)){
            ans[i]=m;
            f[i]=find(i+1);
        }
        m--;
    }
    for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
    return 0;
}

本文作者:归游

本文链接:https://www.cnblogs.com/guiyou/p/18697105

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   归游  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起