返回顶部

Codeforces Round #679 (Div. 2, based on Technocup 2021 Elimination Round 1)

A

给定\(n\)个数分别为\(a_1,a_2,...,a_n\),构造出一组\(b_1,b_2,...,b_n\)使得\(a_1 \times b_1 + a_2 \times b_2 + ... + a_n \times b_n = 0\) \((a_i\)\(b_i\)必须是非\(0\)的数且不超过\(100)\)\(n\)为偶数。

\(n\)为偶数作为切入点,直接输出\(a_{i+1}\)\(-a_i\),使得\(a_i \times a_{i + 1} + a_{i + 1} \times -a_i = 0\)。同理,输出\(-a_{i + 1}\)\(a_i\)也可。


#include <bits/stdc++.h>
using namespace std;
const int N = 100 + 20;
int n;

int main()
{
	int T;
	scanf("%d", &T);
	while(T --)
	{
		scanf("%d", &n);
		for(int i = 1; i <= n; i += 2)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			printf("%d %d ", -y, x);
		}
		puts("");
	}
	//system("pause");
	return 0;
}

B

对于一个\(n \times m\)的矩阵,给出它每行的顺序和它每列的顺序,还原这个矩阵。

因为矩阵里的数一定是不重复的从\(1\)\(n \times m\)的数,对于每个二维坐标,记录每个数的行和列,然后反过来用二维数组的行列对应这个值,输出即可。


#include <bits/stdc++.h>
using namespace std;
const int N = 500 + 20;

int r[N * N], c[N * N], a[N][N];
int n, m, x;

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++ i)
            for(int j = 1; j <= m; ++ j)
                scanf("%d", &x), c[x] = j;
        for(int i = 1; i <= m; ++ i)
            for(int j = 1; j <= n; ++ j)
                scanf("%d", &x), r[x] = j;
        for(int i = 1; i <= n * m; ++ i) a[r[i]][c[i]] = i;
        for(int i = 1; i <= n; ++ i)
            for(int j = 1; j <= m; ++ j)
                printf("%d%c", a[i][j], j == m ? '\n' : ' ');
    }
    //system("pause");
    return 0;
}

C

给定\(n\)个数,和\(6\)个基准数,对于\(n\)个数中的每一个,必须选择\(6\)个数中的一个作差,使得到的\(n\)个差值中最大差值和最小差值的差最小。

\(n\)个数中每一个和\(6\)个基准数都做一下差,并标记一下这是第\(i\)个数与基准数得到的差,将这个差从小到大排序,然后双指针扫序列,当双指针区域里包含\(n\)个数得到的差\((\)每个数至少\(1\)\()\)时,并且这个区域不能再缩小时,统计答案,扫完一遍序列即可得到最优解。
写法:左指针每次固定右移,右指针往右扩展。


#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 1e5 + 20;
int n, a[7], b[N];

int cnt[N], q;
void add(int x)
{
    ++ cnt[x];
    if(cnt[x] == 1) ++ q;
}
void rem(int x)
{
    -- cnt[x];
    if(cnt[x] == 0) -- q;
}

int main()
{
    for(int i = 1; i <= 6; ++ i) scanf("%d", &a[i]);
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i) scanf("%d", &b[i]);
    vector<pii> vec;
    for(int i = 1; i <= n; ++ i)
        for(int j = 1; j <= 6; ++ j)
            vec.push_back(make_pair(b[i] - a[j], i));
    sort(vec.begin(), vec.end());
    int res = 1e9;
    int l = 0, r = -1;
    while(l < 6 * n)
    {
        while(r + 1 < 6 * n && q != n) add(vec[++ r].second);
        if(q == n) res = min(res, vec[r].first - vec[l].first);
        rem(vec[l ++].second);
    }
    printf("%d\n", res);
    //system("pause");
    return 0;
}

D

给定\(n\)件物品,价格分别为\(1,2,...,n\),给定\(2 \times n\)次操作:

\(1:+\) 将一件物品放置到货架上

\(2: - x\) 将物品\(x\)卖出

卖出物品的规则为每次只能售出价格最低的物品,请根据操作还原放置物品的顺序。

对于每一次卖出,一定是选择最近的最近的放置,这次放置的限制比较小,这样选取答案一定是最优。
使用栈去维护这些操作,每次\(+\)操作,将这是第几个放入和值的下限\((\)下限不能被取到\()\),初始化下限为0.
每次\(-\)操作,如果栈中已经没有元素或者当前栈顶的下限 \(>=\)这个值,则不合法,直接输出NO.
如果可以取出,就给栈顶元素位置填上当前取出的数,并对新栈顶修改下限,下限为当前取出的\(x\)和原来下限的最大值。


#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 20;

int res[N],cnt;
struct zt
{
    int pos, val;
};
stack<zt> s;

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= 2 * n; ++ i)
    {
        char op[2];
        int x;
        scanf("%s", op);
        if(*op == '+') s.push({++ cnt, 0});
        else if(*op == '-')
        {
            scanf("%d", &x);
            if(s.empty() || x <= s.top().val) 
            {
                printf("NO\n");
                return 0;
            }
            res[s.top().pos] = x;
            s.pop();
            if(!s.empty()) s.top().val = max(s.top().val, x);
        }
    }
    printf("YES\n");
    for(int i = 1; i <= n; ++ i) printf("%d ", res[i]);
    puts("");
    //system("pause");
    return 0;
}

E

每次施放技能,可以对敌人造成\(a\)点伤害,在接下来的\(c\)秒时间内,每秒敌人可以恢复\(b\)点血,技能冷却时间为\(d\)秒,问可以击杀敌人的最大血量是多少,如果可以击杀任意血量的敌人,输出\(-1\).

首先考虑输出\(-1\)的情况,对于一次施放技能来说,如果总恢复血量\(b \times c\)都不如伤害\(a\)高,那么显然不论\(d\)冷却有多久,都可以通过很多次的技能来击杀任意血量的怪物。
故当\(a > b \times c\) ,答案一定是\(-1\).
考虑其他情况,当\(a >= b \times c\),则击杀怪物血量一定有上限,在先不考虑第一次施放技能的前提下,为了求出可以击杀的最大血量,总共可以让怪物恢复的时间为 \(t = a / b\),在这段时间里,可以施放技能的次数为\(k = t / d\),加上第一次施放技能总共打掉的血量为\(a \times (k + 1)\),总共回复的血量为\(k \times d \times b + (k - 1) \times d \times b+ ... + d \times b = b \times k \times (k + 1) \times d / 2\).
故答案为

\[ ans = a \times (k + 1) - b \times k \times (k + 1) \times d / 2 \]


#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a, b, c, d;

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
        if(a > b * c) printf("-1\n");
        else 
        {
            LL t = a / b;
            LL k = t / d;
            LL res = a * (k + 1) - b * d * k * (k + 1) / 2;
            printf("%lld\n", res);
        }
    }
    //system("pause");
    return 0;
}

2020.11.17

posted @ 2020-11-17 15:31  __October  阅读(79)  评论(0编辑  收藏  举报