CF div2 601

CF div2 601

比赛AB两个题,菜,B题据说是个错的。emmm

题目链接

 

A题,水题

#include <bits/stdc++.h>

using namespace std;

int main(int argc, char const *argv[])
{
	//freopen("A.txt","r",stdin);
	int t;
	cin>>t;
	while(t--) {
		int a,b;
		cin>>a>>b;
		int c=abs(a-b);
		int ans = c/5;
		c=c%5;
		ans+=c/2;
		c=c%2;
		ans+=c;
		cout<<ans<<endl;
	}
	return 0;
}

B题,给你n个人,每个人有一个冰箱,m条链子,链接n个冰箱,当一个人有链接这个冰箱的所有链子的密码,可以打开这个冰箱,求每个冰箱都是每个人私有的链子权值和的最小代价。

明显,需要有环,直接一个大环。因为可以连重边,所以剩下的m-n条边全部连权值最小的,

但是赛后,好像有情况不符合,变成了一个错题。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int maxn = 1e3+10;

struct node
{
	int x;
	int id;
}a[maxn];

bool cmp(node A,node B) {
	return A.x<B.x;
}

int main()
{
	//freopen("B.txt","r",stdin);
	int t;
	scanf("%d",&t);
	while(t--) {
		int n,m;
		scanf("%d%d",&n,&m);
		int ans = 0;
		rep(i,1,n) {
			cin>>a[i].x;
			ans+=a[i].x;
			a[i].id=i;
		}
		if(m<n||n==2) {
			puts("-1");
			continue;
		}
		if(m==n) {
			printf("%d\n",ans*2);
			rep(i,1,n) {
				if(i==n) printf("%d 1\n",i);
				else printf("%d %d\n",i,i+1);
			}
			continue;
		}
		ans*=2;
		m-=n;
		int f=0;
		sort(a+1,a+1+n,cmp);
		ans=ans+m*(a[1].x+a[2].x);
		printf("%d\n",ans);
		rep(i,1,n) {
			if(i==n) printf("%d 1\n",i);
			else printf("%d %d\n",i,i+1);
		}
		while(m--) {
			printf("%d %d\n",a[1].id,a[2].id);
		}
	}
	return 0;
}

 

C题,意思是给你一个n个数排列,构成n-2个三元组(连续),然后可以打乱三元组的顺序和三元组内元素的顺序。叫你还原这个排列。

容易知道,最开始和最后的元素出现次数为1,还有两个元素(出现次数)分别在最开始和最后的元素所在三元组中,剩下的元素出现次数全为3。

首先,找到出现次数为1 的,根据这个三元组继续往后推,直到推到最后一个。

记录每一组的三个元素和每个元素出现的组数,然后往后推,记录一下前面的组数,找当前b,c出现组数相同的且和前面不同的。此时将这个组的另外一个元素推进答案,然后a=b,b=c;c=新元素。

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5+10;
vector<int>p[maxn];
int e[maxn][4];
int cnt[maxn];
vector<int>ans;
int main(int argc, char const *argv[])
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n-2;i++) {
        int x,y,z;
        cin>>x>>y>>z;
        cnt[x]++;
        cnt[y]++;
        cnt[z]++;
        e[i][1]=x;
        e[i][2]=y;
        e[i][3]=z;
        p[x].push_back(i);
        p[y].push_back(i);
        p[z].push_back(i);
    }
    int start;
    for(int i=1;i<=n;i++) {
        if(cnt[i]==1) {
            start = i;
            break;
        }
    }
    ans.push_back(start);
    int id;
    for(int i=0;i<p[start].size();i++) {
        id = p[start][i];
    }
    int x = e[id][1];
    int y = e[id][2];
    int z = e[id][3];
    int b=0,c=0;
    int a=start;
    if(x!=start) {
        if(b==0) b=x;
        else c=x;
    }
    if(y!=start) {
        if(b==0) b=y;
        else c=y;
    }
    if(z!=start) {
        if(b==0) b=z;
        else c=z;
    }
    if(cnt[b]==3) {
        swap(b,c);
    }
    ans.push_back(b);
    ans.push_back(c);
    int m = n;
    m-=3;
    while (m--) {
        int f=0;
        for(int i=0;i<p[b].size();i++) {
            for(int j=0;j<p[c].size();j++) {
                if(p[b][i]==p[c][j]&&p[b][i]!=id) {
                    id=p[b][i];
                    f=id;
                    a=b;
                    b=c;
                    break;
                }
            }
            if(f) break;
        }
        for(int i=1;i<=3;i++) {
            if(e[f][i]!=a&&e[f][i]!=b) {
                ans.push_back(e[f][i]);
                c=e[f][i];
                break;
            }
        }
    }
    for(auto e:ans) {
        printf("%d ",e);
    }
    printf("\n");
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值