Codeforces Global Round 14补题

本文详细解析了Codeforces Global Round 14中涉及的四道题目,包括A题PhoenixandGold的前缀和处理,B题PhoenixandPuzzle的几何构形分析,C题PhoenixandTowers的贪心策略,以及D题PhoenixandSocks的袜子配对问题。通过代码展示和解题思路,帮助读者理解贪心算法和数组操作在解决竞赛编程问题中的应用。
摘要由CSDN通过智能技术生成


比赛link-》戳我看题

A. Phoenix and Gold

题意解读

题目连接:https://codeforces.com/contest/1515/problem/A
题目的大概意思就是说给你n个不重复数字,然后给你一个k,让你求是否存在一个排列,使得这个排列的前缀和中不出现k
当时自己竟然没做出来,我当时在想先从最小开始输出还是从最大开始输出,然后交了两发wa了之后我还试了一下随机打乱数组,后来自己的思路就困在了如果遇到前缀和为k的数,先保留,所有数字输出完,在输出这个数,但不知道交上去还是不对。
比赛结束看了题解才知道,直接按照原来的祖烈输出就行了,只要遇到前缀和为k的数字,就交换这个数字和下一个,另外需要注意的就是,只要这n个数字的综合不是k,总有办法避开k的。

代码展示

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,k;
        ll sum = 0;

        cin>>n>>k;
        int a[n+2];
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            sum += a[i];
        }
        if(sum == k)
            cout<<"NO\n";
        else
        {
            cout<<"YES\n";
            for(int i=1;i<=n;i++)
            {
                if(a[i] == k)
                {
                    swap(a[i],a[i+1]);
                }
                if(i==1)
                {
                    cout<<a[i];
                }
                else
                {
                    cout<<" "<<a[i];
                }
                k -= a[i];
            }
            cout<<endl;
        }
    }
    return 0;
}

B. Phoenix and Puzzle

题目连接:https://codeforces.com/contest/1515/problem/B

题意理解

题意就是说给你一个边长为等边直角三角形,问n块是否可以组成一个正方形。
由正三角形组成正方形只有两种方法,要么拿直角放中间,要么把直角放在正方形的顶点,内部还可以嵌套一个旋转45度的正方形,把这两种情况画一下,列出来所需要的三角形个数,要么2powr(i,2) == n 要么 4powr(i,2) == n,另外,不需要暴力的从1到n判断,只需要到根号n就可以了。

代码展示

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<cstring>
#include<map>
#include<string>
typedef long long ll;
using namespace std;

const ll maxn = 1e9;
ll powr(int a,int n) {//快速幂
	int ans = 1;
	while(n) {
		if(n&1) {
			ans *= a;
		} else
			a *= a;
		n>>=1;
	}
	return ans;
}
int main() {

	int t;
	cin>>t;
	while(t--) {
		ll n;
		cin>>n;
		int flag1 = 1;
		for(int i=1; powr(i,2)<= n; i++) {//只有这两种情况
			if(2*powr(i,2) == n || 4*powr(i,2) == n) {
				flag1 = 0;//出现一种情况就行
			}
		}
		if(flag1)
			cout<<"NO\n";
		else
			cout<<"YES\n";
	}
	return 0;
}

C. Phoenix and Towers(贪心)

题意解读

题目连接:https://codeforces.com/contest/1515/problem/C
给n个大于等于1且小于等于x的高度值,将它们分配给m个位置,每个位置的高度为分配的数值之和,要使得m个位置两两之间高度差不超过x。
我没做出来,网上看人家的博客。
解题思路:边输入边输出,每次拿出当前高度最低的位置,然后把当前得到的高度值加在上面。

证明正确性:
每次增加最低位置的高度后,整体状态都符合条件。
假设当前这m个位置符合条件,则最高位置的高度减去最低位置的高度不大于x,当前最低位置和其他任意位置的高度差都大于等于0。
然后给最低位置加上一个大于等于1且小于等于x的高度值,那么有两种情况,一是原来最低位置成了新的最高位置,第二低的位置成了最低位置,显然两者差值不大于x,二是原来最低位置的新值不超过原来最高位置,但是新的最低位置的高度并不小于原来最低位置的高度。两种情况都符合条件。

代码展示

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N  = 100005;
int t,n,m,x,h[N],y[N];
struct node{//定义结构体来存储每一个Tower的位置和当前高度
    int h,id;
    node(int _h = 0,int _id = 0):h(_h),id(_id){}//初始化函数,记住就行了
}p[N];

bool operator > (const node & a,const node & b)//重载>运算符,因为下边用到了优先队列
{
    return a.h > b.h;
}

int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n>>m>>x;
        cout<<"YES\n";
        priority_queue<node,vector<node>,greater<node> >pq;//这里按照高度由小到大排,如果默认less就重载小于号,如果默认greater就重载大于号
        for(int i=1;i<=m;i++)
            pq.push(node(0,i));//初始化所有的Tower的高度是0;
        for(int i=1;i<=n;i++)
        {
            cin>>p[i].h;
            node tmp = pq.top();//取出高度最低的tower
            pq.pop();
            printf("%d%c",tmp.id,i==n? '\n' : ' ');//放在最低的那个Tower上
            pq.push(node(tmp.h + p[i].h,tmp.id));//放好后在放回优先队列,他会自动排序的
        }
    }

    return 0;
}

D. Phoenix and Socks

https://codeforces.com/contest/1515/problem/D

题意解读

有n(偶数)只袜子,前l只是左脚的,后r只为右脚的,每个袜子都有一个颜色,需要把所有的袜子成对(每个袜子必须有一个左脚和一个右脚相对应,且颜色相同)
可以通过一些操作来实现,每个操作需要1元
1.给一个袜子换一个颜色
2.给一个左脚的袜子变为右脚的
3.给一个右脚的袜子变为左脚的
求最小代价

题目类型:贪心
  解析:
  贪心思想,首先,能不花钱就不花钱,看看能不能左右匹配。
  设对于左右不同颜色的直接匹配为硬匹配,花费2元。不花钱的处理完了之后,若存在L != R的情况,此时不能直接硬匹配。如果L多,就在1~L中找找,能不能改方向,不改颜色匹配。因为此时硬匹配不但要改颜色而且要改方向,不如先在L中看看能不能同方向匹配,能的话绝对是赚的,每匹配一对,最终少改一次颜色。
  最后硬匹配即可。
  自己还是写不出来,只会参考别人的代码,然后对照理解(55555~)

代码解析

//这不是我的代码,照着别的博主看的
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 202020;

int n,t,l,r,a[N],col[N],cor[N];

int main()
{
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
         int finish = 0 , ans = 0;
        cin >> n >> l >> r ;
        for(int i = 1 ; i <= n ; ++i){
            cin >> a[i] ;
            if(i <= l)col[a[i]]++;
            else cor[a[i]]++;
        }
        int nl = l,nr = r;
        //处理左右匹配的情况
        for(int i=1;i<=l;i++)
        {
            if(col[a[i]] && cor[a[i]])
            {
                col[a[i]] --;
                cor[a[i]] --;
                nl--;
                nr--;
            }
        }

        if(nl >= nr){
            ///处理左匹配
            for(int i = 1 ; i <= l ; ++i){
                if(col[a[i]] >= 2 && nl > nr){
                    col[a[i]] -= 2;
                    nl-=2;
                    ans++;
                }
            }
            ans += (nl-nr)/2 + (nl+nr)/2;
        }
        //处理右匹配的情况
        else{
            for(int i=l+1;i<=n;i++)
            {
                if(cor[a[i]] >= 2 && nr > nl){
                    cor[a[i]] -= 2;
                    nr-=2;
                    ans++;
                }
            }
            ans += (nr-nl)/2 + (nr+nl)/2;
        }

        cout<<ans<<endl;
        for(int i=1;i<=n;i++)
        {
            col[i] = cor[i] = 0;
        }

    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值