Codefrces Beta Round #3

题目链接

A.Shortest path of the king

题目大意:
  • 有一个棋盘(x: A-H,y:1-8),棋子可以向与其所在位置有公共顶点的其他位置走动,求从起点到终点的最少步数和路径。
Input
a8 
h1
Output:
7 
RD 
RD 
RD 
RD 
RD 
RD 
RD
思路:
  • 尽量斜着走,注意考虑边界
代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

int main()
{
    string from, to;
    cin >> from >> to;

    vector<string> path;
    path.clear();

    string now = from;
    while (now != to)
    {
        if (to[0] > now[0] && to[1] < now[1])
        {
            path.push_back(string("RD"));
            now[0] += 1;
            now[1] -= 1;
        }
        else if (to[0] > now[0] && to[1] > now[1])
        {
            path.push_back(string("RU"));
            now[0] += 1;
            now[1] += 1;
        }
        else if (to[0] < now[0] && to[1] > now[1])
        {
            path.push_back(string("LU"));
            now[0] -= 1;
            now[1] += 1;
        }
        else if (to[0] < now[0] && to[1] < now[1])
        {
            path.push_back(string("LD"));
            now[0] -= 1;
            now[1] -= 1;
        }
        else if (to[0] < now[0])
        {
            path.push_back(string("L"));
            now[0] -= 1;
        }
        else if (to[0] > now[0])
        {
            path.push_back(string("R"));
            now[0] += 1;
        }
        else if (to[1] > now[1])
        {
            path.push_back(string("U"));
            now[1] += 1;
        }
        else if (to[1] < now[1])
        {
            path.push_back(string("D"));
            now[1] -= 1;
        }
    }

    int size = path.size();
    cout << size << endl;
    for (int i = 0; i < size; i++)
        cout << path[i] << endl;

    return 0;
}

B. Lorry

题目大意:
  • 有一个卡车容积为 v v v,有2种船,皮划艇(kayak) i i i占面积为1,可承载力为 p i p_i pi,双体船(catamaran) j j j占面积为2,可承载力为 p j p_j pj。最后求该卡车应该选择运哪些船使得这些船所占空间不大于 v v v,且可承载力最大。
输入:
  • n n n为船数量, v v v为卡车容积。 ( 1   ≤   n   ≤   1 0 5 ; 1   ≤   v   ≤   1 0 9 ) (1 ≤ n ≤ 10^5; 1 ≤ v ≤ 10^9) (1n105;1v109)
  • 输入n行,每行为船的类型 t i t_i ti和可承载力 p i p_i pi ( 1   ≤   t i   ≤   2 ; 1   ≤   p i   ≤   1 0 4 ) (1 ≤ t_i ≤ 2; 1 ≤ p_i ≤ 10^4) (1ti2;1pi104). 1为kayak,2为catamaran
输出:
  • 最后的最大的可承载力
  • 选择了哪些船
思路:
  • 版本1:按照 capacity/type 从大到小排序,然后每次选择最大的。但是考虑到这样一个问题,就是最后剩下1。这种情况就可以放弃一个1选择1个2。这样改了之后代码还是不对。这样考虑很难考虑全,代码不好写。
  • 最终版:
  • 考虑 特殊情况: v v v为奇数时,那个体积为1且可承载力最大的kayak是一定会被选择的。可以先进行选择,注意这里kayak可能数量为0
  • 剩下情况: 将体积为1的两两相加,相加后的值去和原本体积为2的比,然后每次选择较大的那个即可。
代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <unordered_set>
using namespace std;

struct Node
{
    int id1;
    int id2;
    int capacity;
};

vector<Node> boat;
vector<Node> kayak;
vector<int> choose;

bool cmp(const Node& A, const Node& B)
{
    return A.capacity > B.capacity;
}

int main()
{
    int n, v;
    cin >> n >> v;

    boat.clear();
    kayak.clear();
    choose.clear();

    int type, capa;
    Node tmp;
    for (int i = 1; i <= n; i++)
    {
        cin >> type >> capa;
        tmp.id1 = i;
        tmp.id2 = -1;
        tmp.capacity = capa;
        if (type == 1)
            kayak.push_back(tmp);
        else
            boat.push_back(tmp);
    }

    sort(kayak.begin(), kayak.end(), cmp);

    int res = 0;
    int start = 0;
    int sizeK = kayak.size();

    if ((v & 1) && (sizeK > 0))
    {
        v -= 1;
        res += kayak[0].capacity;
        choose.push_back(kayak[0].id1);
        start++;
    }

    for (int i = start; i < sizeK; i += 2)
    {
        if (i + 1 < sizeK)
        {
            tmp.id1 = kayak[i].id1;
            tmp.id2 = kayak[i+1].id1;
            tmp.capacity = kayak[i].capacity + kayak[i+1].capacity;
        }
        else if (i + 1 == sizeK)
        {
            tmp = kayak[i];
        }
        boat.push_back(tmp);
    }

    sort(boat.begin(), boat.end(), cmp);
    int sizeB = boat.size();

    for (int i = 0; i < sizeB; i++)
    {
        if (v < 2)
            break;

        v -= 2;
        res += boat[i].capacity;
        choose.push_back(boat[i].id1);
        choose.push_back(boat[i].id2);
    }
    cout << res <<  endl;

    for (int i = 0; i < choose.size(); i++)
        if (choose[i] != -1)
        cout << choose[i] << " ";
    cout << endl;
    return 0;
}

C. Tic-tac-toe

题目大意:
  • 3 * 3的棋盘,2个人相互放棋子,谁先达到3个成行,成列或对角线即为赢。给出现在棋局,判断现在情况。
不同情况:

假设A先手,B后手

  • legal: A和B的相差数量始终在(0,1)之间。若有人赢了,立刻结束比赛。棋盘上只有可能一个人的棋子摆放完成。
代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <set>
#include <unordered_set>
using namespace std;

char m[5][5];
typedef pair<int, int> pii;
vector<pii> one, two;

bool oneLine(vector<pii>A)
{
    if (A[0].first + A[2].first == 2 * A[1].first && A[0].second + A[2].second == 2 * A[1].second)
        return true;
    return false;
}

bool judgeOK(int sizeX, vector<pii> v)
{
    vector<pii> tmp;
    int total = (1 << sizeX);
    bool line = false;
    int num;
    for (int i = 0; i < total; i++)
    {
        tmp.clear();
        num = 0;
        for (int j = 0; j < sizeX; j++)
        {
            if (((1 << j) & i) != 0)
            {
                num++;
                tmp.push_back(v[j]);
            }
        }

        if (num == 3)
            line = oneLine(tmp);

        if (line)
            return true;
    }
    return false;
}

int main()
{
    for (int i = 0; i < 3; i++)
        scanf("%s", m[i]);

    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
        {
            if (m[i][j] == 'X')
                one.push_back(make_pair(i, j));
            else if (m[i][j] == '0')
                two.push_back(make_pair(i, j));
        }
    int sizeX = one.size();
    int size0 = two.size();

    sort(one.begin(), one.end());
    sort(two.begin(), two.end());

    string res;
    string oneOK = "", twoOK = "";
    if (size0 > sizeX || sizeX - size0 >= 2)
        res = "illegal";
    else
    {
        if (sizeX >= 3)
        {
            bool line = judgeOK(sizeX, one);
            if (line)
                oneOK = "the first player won";
        }
        if (size0 >= 3)
        {
            bool line = judgeOK(size0, two);
            if (line)
                twoOK = "the second player won";
        }
        if (oneOK != "" && sizeX == size0)
            res = "illegal";
        else if (twoOK != "" && sizeX > size0)
            res = "illegal";
        else if (oneOK != "")
            res = oneOK;
        else if (twoOK != "")
            res = twoOK;
        else if (sizeX == size0)
            res = "first";
        else if (sizeX + size0 == 9)
            res = "draw";
        else if (sizeX > size0)
            res = "second";

    }
    cout << res << endl;

    return 0;
}

D.Least Cost Bracket Sequence

题目大意:
  • 给一串括号的序列,该包含()?。然后将?替换成(或者) , 使得该序列成为一个常规的括号序列。
  • 对于每个 ?,给出用()替换的成本,在所有可能的情况中,选择成本最低的。
输入:
  • 一行包含偶数长度的非空模式,由()?组成,长度不超过 5 ⋅ 1 0 4 5 \cdot 10^4 5104 。其中? 个数为 m m m
  • 输入 m m m行, a i , b i ( 1   ≤   a i ,     b i   ≤   1 0 6 ) a_i , b_i (1 ≤ a_i,  b_i ≤ 10^6) ai,bi(1ai,bi106) a i a_i ai为替换成(的成本, b i b_i bi为替换成)的成本
输出:
  • 最低成本(若没有方案则输出-1)
  • 替换后的括号序列
input:
(??)
1 2
2 8
output:
4
()()
思路:
  • 我不太会,想到唯一判断括号序列合法性的是用栈。所以百度了一下……
  • 判断序列合法性:一个前缀和 s u m sum sum,遇到(就+1,遇到)就-1。在遍历序列中整个过程不存在 s u m &lt; 0 sum&lt;0 sum<0 且最后 s u m = 0 sum=0 sum=0 则该括号序列为合法。
  • 贪心:先假设所有 ?都是),当碰到 s u m &lt; 0 sum&lt;0 sum<0的情况时判断前方是否有 ?可以替换成(。如果没有,则直接判不合法,否则选择使成本最低的替换成(
  • 如何选择使最后成本最低:选择left - right 最小的,这个值表示了由? -> ) -> ( 后一步过程可以减少的最大值(前一步每个都要经历)。而这一步使用优先队列实现。
  • 注意:优先队列默认top为最大,重载<时函数内要用>;注意数值范围,int大概 1 0 9 10^9 109,这里超了,用long long
  • 总结:好像是我没碰到过的贪心套路……get了一点不过好像不太明白为什么。就是贪心那里为什么就全都替换成),我知道替换成(不对,可是以后碰到类似情况可能递推不来。
代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

typedef long long llong;

struct Node
{
    int id;
	int left;
	int right;
	friend bool operator < (const Node& A, const Node& B)
	{
		return (A.left - A.right) > (B.left - B.right);
	}
};

int main()
{
	string str;
	while (cin >> str)
	{
	    vector<int> id;
		int cnt = 0;
		for (size_t i = 0; i < str.length(); ++i)
		{
			if (str[i] == '?')
				{
				    ++cnt;
				    id.push_back(i);
				}
		}

		vector<Node> vec;
		Node tmp;
		for (size_t i = 0; i < cnt; ++i)
		{
			cin >> tmp.left >> tmp.right;
			tmp.id = i;
			vec.push_back(tmp);
		}

		int sum = 0;
		llong res = 0;
		cnt = -1;
		priority_queue<Node> pq;	//increase order

		for (size_t i = 0; i < str.length(); ++i)
		{
			if (str[i] == '(')
				sum += 1;
			else if (str[i] == ')')
				sum -= 1;
			else
			{
				++cnt;
				pq.push(vec[cnt]);
				res += vec[cnt].right;
				sum -= 1;
				str[i] = ')';
			}

			if (sum < 0 && pq.empty())
                break;
            else if (sum < 0)
			{
                Node tmp = pq.top();
                pq.pop();
                res += tmp.left - tmp.right;
                str[id[tmp.id]] = '(';
                sum += 2;
			}
		}

		if (sum != 0)
			res = -1;

		cout << res << endl;
		if (res != -1)
			cout << str << endl;
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值